8

尝试发出网络请求时,出现错误

finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled"

如果我使用它URLSession.shared.dataTask代替URLSession.shared.dataTaskPublisher它将在 IOS 13.3 上运行。

这是我的代码:

return  URLSession.shared.dataTaskPublisher(for : request).map{ a in
    return a.data
}
.decode(type: MyResponse.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()

此代码适用于 IOS 13.2.3。

4

3 回答 3

12

您在这里有两个问题:1. 就像@matt 所说,您的出版商活得不够长。您可以将 存储AnyCancellable为实例var,或者我喜欢做的(并且似乎是一个 redux 最佳实践)是使用store(in:)aSet<AnyCancellable>来保持它并在对象被释放时自动清理它。2.为了启动您需要的实际网络请求sinkassign值。

所以,把这些放在一起:

var cancellableSet: Set<AnyCancellable> = []

func getMyResponse() {
  URLSession.shared.dataTaskPublisher(for : request).map{ a in
    return a.data
  }
  .decode(type: MyResponse.self, decoder: JSONDecoder())
  .receive(on: DispatchQueue.main)
  .replaceError(with: MyResponse())
  .sink { myResponse in print(myResponse) }
  .store(in: &cancellableSet)
}
于 2019-12-11T10:46:59.760 回答
10

您没有显示足够的代码,但根据症状很清楚问题出在哪里:您的发布者/订阅者对象的寿命不够长。我敢说你的代码总是错的,它似乎成功只是一个怪癖。确保您的发布者,尤其是您的订阅者保留在长期对象中,例如实例属性,以便网络通信有时间进行。

这是一个如何使用数据任务发布者的工作示例:

class ViewController: UIViewController {
    let url = URL(string:"https://apeth.com/pep/manny.jpg")!
    lazy var pub = URLSession.shared.dataTaskPublisher(for: url)
        .compactMap {UIImage(data: $0.data)}
        .receive(on: DispatchQueue.main)
    var sub : AnyCancellable?
    override func viewDidLoad() {
        super.viewDidLoad()
        let sub = pub.sink(receiveCompletion: {_ in}, receiveValue: {print($0)})
        self.sub = sub
    }
}

打印出来<UIImage:0x6000008ba490 anonymous {180, 206}>,这是正确的(您可以通过自己访问该 URL 看到)。

我要说的是,如果你不说self.sub = sub,你会得到你报告的错误:订阅者sub,它只是一个本地的,立即不存在并且网络事务被提前取消(你的错误报道)。

编辑我认为代码是在.store(in:)方法存在之前编写的;如果我今天写它,我会使用它而不是sub属性。但原理是一样的。

于 2019-12-11T06:52:11.000 回答
0

我需要将可取消集移动到订阅者正在执行的功能范围“上方”。当可取消集与订阅者的功能具有相同的范围时,这在 iOS 13.2 中运行良好,但在 13.3 中停止工作。dataTaskPublisher 因上述错误而取消。可取消集应该“退出”订阅者是有道理的。开发者错误。学过的知识。

于 2019-12-11T18:41:33.613 回答