AnyCancellable.store(in:) 与合并

AnyCancellable.store(in:) with Combine

假设您在 AnyCancellable 上使用内置的 .store(in:) 方法,如下所示:

private var subscriptions = Set<AnyCancellable>()

let newPhotos = photos.selectedPhotos
newPhotos
  .map { [unowned self] newImage in
    return self.images.value + [newImage]
  }
  .assign(to: \.value, on: images)
  .store(in: &subscriptions)

如果您的应用经常执行此操作 - 发布商完成后是否会删除这些应用?

此外,如果我决定改用这种方法:

private var newPhotosSubscription: AnyCancellable?

self.newPhotosSubscription = newPhotos
  .map { [unowned self] newImage in
    self.images.value + [newImage]
  }
  .assign(to: \.value, on: images)

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

一个Set<T>T一无所知,当然也不知道它是一个Combine AnyCancellablestore(in:) 的文档没有说它将监视订阅并将其删除。

因此,完成后不会自动发生任何事情,但您可以自己将其从 Set 中删除。

如果您通过删除对 AnyCancellable 的所有引用来释放它(Swift 中没有 GC),则您已取消订阅。它不会等待完成。

特定类型的可取消(例如,您创建的)有可能决定它始终完成并在解除分配之前完成。

为了实现仅在前一个订阅已完成时才创建新订阅的目标,同时还要确保前一个订阅在完成后立即丢弃,最好将引用存储到你的 AnyCancellable 直接,而不是 Set.

您应该检查您是否已经有订阅,如果没有则只开始订阅,然后使用 sink 而不是 assign,如果您收到完成,请设置AnyCancellablenil 的引用。这将确保您当前的订阅完成后,您可以开始新的订阅。

private var newPhotosSubscription: AnyCancellable?

if newPhotosSubscription == nil {
    newPhotosSubscription = newPhotos
        .map { [unowned self] newImage in
            self.images.value + [newImage]
        }
        .sink(receiveValue: { [weak self] value in
            self.images.value = value
        }, receiveCompletion: { [weak self] _ in
            newPhotosSubscription = nil
        })
    }
}

Dávid Pásztor 的解决方案很接近,但存在竞争条件。具体来说,假设 newPhotos 发布者同步完成, sink 方法 returns 之前。一些出版商以这种方式运作。 JustResult.Publisher 都可以,等等。

在那种情况下,完成块在 sink returns 之前运行。然后,sink returns 一个 AnyCancellable 存储在 newPhotosSubscription 中。但是订阅已经完成,所以 newPhotosSubscription 永远不会设置回 nil。

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

这是解决此问题的一种方法:跟踪订阅是否已完成。在sinkreturns之后检查,在设置newPhotosSubscription.

之前
private var ticket: AnyCancellable? = nil

if ticket == nil {
    var didComplete = false
    let newTicket = newPhotos
        .sink(
            receiveValue: { [weak self] in
                self?.images.value.append([=10=])
            },
            receiveCompletion: { [weak self] _ in
                didComplete = true
                self?.ticket = nil
            }
        )
    if !didComplete {
        ticket = newTicket
    }
}

Everytime I call the method again, it override the AnyCancellable, what happens to the previous one? Does it still complete before being deallocated?

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