AnyCancellable.store(in:) 与合并

Jay*_*ing 8 swift combine

让\xe2\x80\x99s 假设您正在 AnyCancellable 上使用内置.store(in:)方法,如下所示:

\n
private var subscriptions = Set<AnyCancellable>()\n\nlet newPhotos = photos.selectedPhotos\nnewPhotos\n  .map { [unowned self] newImage in\n    return self.images.value + [newImage]\n  }\n  .assign(to: \\.value, on: images)\n  .store(in: &subscriptions)\n
Run Code Online (Sandbox Code Playgroud)\n

如果您有一个经常执行此操作的应用程序 - 发布商完成后这些内容是否会被删除?

\n

另外,如果我决定采用这种方法:

\n
private var newPhotosSubscription: AnyCancellable?\n\nself.newPhotosSubscription = newPhotos\n  .map { [unowned self] newImage in\n    self.images.value + [newImage]\n  }\n  .assign(to: \\.value, on: images)\n
Run Code Online (Sandbox Code Playgroud)\n

每次我再次调用该方法时,它都会覆盖 AnyCancellable,前一个会发生什么?它在被释放之前是否仍然完成?

\n

rob*_*off 7

D\xc3\xa1vid P\xc3\xa1sztor 的解决方案很接近,但它有一个竞争条件。具体来说,假设发布者在方法返回之前newPhotos同步完成。有些出版商就是这样运作的。两者都是如此。sinkJustResult.Publisher

\n

在这种情况下,完成块会在sink返回之前运行。然后,sink返回AnyCancellable存储在 中的一个newPhotosSubscription。但订阅已经完成,因此newPhotosSubscription永远不会被设置回零。

\n

例如,如果您URLSession.DataTaskPublisher在实时代码中使用 a 但替换为Just在某些测试用例中替换了发布者,则测试可能会触发竞争条件。

\n

解决此问题的一种方法是:跟踪订阅是否已完成。sink返回后、设置前检查一下newPhotosSubscription

\n
private var ticket: AnyCancellable? = nil\n\nif ticket == nil {\n    var didComplete = false\n    let newTicket = newPhotos\n        .sink(\n            receiveValue: { [weak self] in\n                self?.images.value.append($0)\n            },\n            receiveCompletion: { [weak self] _ in\n                didComplete = true\n                self?.ticket = nil\n            }\n        )\n    if !didComplete {\n        ticket = newTicket\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

每次我再次调用该方法时,它都会覆盖 AnyCancellable,前一个会发生什么?它在被释放之前是否仍然完成?

\n
\n

前一个(如果有)被取消,因为对旧的唯一引用AnyCancellable被销毁,因此 被AnyCancellable销毁。当 anAnyCancellable被销毁时,它会自行取消(如果尚未取消)。

\n