使用 URLSession 和 Combine 的间歇性结果
intermittent results using URLSession with Combine
我在 playground 中有以下代码 运行,它应该根据随机类别 ID 打印 4 条线索的数组。用于获取线索的类别ID和正确的URL总是打印正确但是,线索结果有时是间歇性打印的,有时是成功的。谁能帮我弄清楚为什么它有时不打印线索数组但 URL 是正确的?
import Foundation
import Combine
// MARK: - ClueElement
struct ClueElement: Codable {
let id: Int
let answer, question: String
let value: Int
let categoryID: Int
let category: Category
enum CodingKeys: String, CodingKey {
case id, answer, question, value
case categoryID = “category_id”
case category
}
}
// MARK: - Category
struct Category: Codable {
let id: Int
let title: String
let cluesCount: Int
enum CodingKeys: String, CodingKey {
case id, title
case cluesCount = “clues_count”
}
}
enum HTTPError: LocalizedError {
case statusCode
case post
}
typealias Clue = [ClueElement]
var cancellable: AnyCancellable?
func loadData() {
let url1 = URL(string: “http://www.jservice.io/api/random”)!
cancellable = URLSession.shared.dataTaskPublisher(for: url1)
.map { [=10=].data }
.decode(type: Clue.self, decoder: JSONDecoder())
.tryMap { category in
guard let categoryID = category.first?.categoryID else { throw HTTPError.post}
guard let cluesCount = category.first?.category.cluesCount else { throw HTTPError.post}
print(“\(categoryID)“)
return (categoryID,cluesCount)
}
.flatMap { (categoryID,cluesCount) in
return getClues(for: categoryID, cluesCount: cluesCount)
}
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
}) { clues in
print(clues)
}
}
func getClues(for id: Int, cluesCount: Int) -> AnyPublisher<Clue, Error> {
let url = URL(string: “http://www.jservice.io/api/clues?category=\(id)&offset=\(cluesCount - 4)“)!
print(url)
return URLSession.shared.dataTaskPublisher(for: url)
.map { [=10=].data }
.decode(type: Clue.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
loadData()
在您的 receiveCompletion:
闭包中放置一个打印语句,您将了解为什么您的代码有时不打印。
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { clues in
print(clues)
}
)
我做的时候看到了这个:
failure(Swift.DecodingError.valueNotFound(Swift.Int, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 2", intValue: 2), CodingKeys(stringValue: "value", intValue: nil)], debugDescription: "Expected Int value but found null instead.", underlyingError: nil)))
我在 playground 中有以下代码 运行,它应该根据随机类别 ID 打印 4 条线索的数组。用于获取线索的类别ID和正确的URL总是打印正确但是,线索结果有时是间歇性打印的,有时是成功的。谁能帮我弄清楚为什么它有时不打印线索数组但 URL 是正确的?
import Foundation
import Combine
// MARK: - ClueElement
struct ClueElement: Codable {
let id: Int
let answer, question: String
let value: Int
let categoryID: Int
let category: Category
enum CodingKeys: String, CodingKey {
case id, answer, question, value
case categoryID = “category_id”
case category
}
}
// MARK: - Category
struct Category: Codable {
let id: Int
let title: String
let cluesCount: Int
enum CodingKeys: String, CodingKey {
case id, title
case cluesCount = “clues_count”
}
}
enum HTTPError: LocalizedError {
case statusCode
case post
}
typealias Clue = [ClueElement]
var cancellable: AnyCancellable?
func loadData() {
let url1 = URL(string: “http://www.jservice.io/api/random”)!
cancellable = URLSession.shared.dataTaskPublisher(for: url1)
.map { [=10=].data }
.decode(type: Clue.self, decoder: JSONDecoder())
.tryMap { category in
guard let categoryID = category.first?.categoryID else { throw HTTPError.post}
guard let cluesCount = category.first?.category.cluesCount else { throw HTTPError.post}
print(“\(categoryID)“)
return (categoryID,cluesCount)
}
.flatMap { (categoryID,cluesCount) in
return getClues(for: categoryID, cluesCount: cluesCount)
}
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
}) { clues in
print(clues)
}
}
func getClues(for id: Int, cluesCount: Int) -> AnyPublisher<Clue, Error> {
let url = URL(string: “http://www.jservice.io/api/clues?category=\(id)&offset=\(cluesCount - 4)“)!
print(url)
return URLSession.shared.dataTaskPublisher(for: url)
.map { [=10=].data }
.decode(type: Clue.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
loadData()
在您的 receiveCompletion:
闭包中放置一个打印语句,您将了解为什么您的代码有时不打印。
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { clues in
print(clues)
}
)
我做的时候看到了这个:
failure(Swift.DecodingError.valueNotFound(Swift.Int, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 2", intValue: 2), CodingKeys(stringValue: "value", intValue: nil)], debugDescription: "Expected Int value but found null instead.", underlyingError: nil)))