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 AnyCancellable
。 store(in:)
的文档没有说它将监视订阅并将其删除。
因此,完成后不会自动发生任何事情,但您可以自己将其从 Set
中删除。
如果您通过删除对 AnyCancellable
的所有引用来释放它(Swift 中没有 GC),则您已取消订阅。它不会等待完成。
特定类型的可取消(例如,您创建的)有可能决定它始终完成并在解除分配之前完成。
为了实现仅在前一个订阅已完成时才创建新订阅的目标,同时还要确保前一个订阅在完成后立即丢弃,最好将引用存储到你的 AnyCancellable
直接,而不是 Set
.
您应该检查您是否已经有订阅,如果没有则只开始订阅,然后使用 sink
而不是 assign
,如果您收到完成,请设置AnyCancellable
对 nil
的引用。这将确保您当前的订阅完成后,您可以开始新的订阅。
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 之前。一些出版商以这种方式运作。 Just
和 Result.Publisher
都可以,等等。
在那种情况下,完成块在 sink
returns 之前运行。然后,sink
returns 一个 AnyCancellable
存储在 newPhotosSubscription
中。但是订阅已经完成,所以 newPhotosSubscription
永远不会设置回 nil。
因此,例如,如果您在实时代码中使用 URLSession.DataTaskPublisher
但在某些测试用例中替换 Just
发布者,则测试可能会触发竞争条件。
这是解决此问题的一种方法:跟踪订阅是否已完成。在sink
returns之后检查,在设置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
被销毁时,它会自行取消(如果尚未取消)。
假设您在 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 AnyCancellable
。 store(in:)
的文档没有说它将监视订阅并将其删除。
因此,完成后不会自动发生任何事情,但您可以自己将其从 Set
中删除。
如果您通过删除对 AnyCancellable
的所有引用来释放它(Swift 中没有 GC),则您已取消订阅。它不会等待完成。
特定类型的可取消(例如,您创建的)有可能决定它始终完成并在解除分配之前完成。
为了实现仅在前一个订阅已完成时才创建新订阅的目标,同时还要确保前一个订阅在完成后立即丢弃,最好将引用存储到你的 AnyCancellable
直接,而不是 Set
.
您应该检查您是否已经有订阅,如果没有则只开始订阅,然后使用 sink
而不是 assign
,如果您收到完成,请设置AnyCancellable
对 nil
的引用。这将确保您当前的订阅完成后,您可以开始新的订阅。
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 之前。一些出版商以这种方式运作。 Just
和 Result.Publisher
都可以,等等。
在那种情况下,完成块在 sink
returns 之前运行。然后,sink
returns 一个 AnyCancellable
存储在 newPhotosSubscription
中。但是订阅已经完成,所以 newPhotosSubscription
永远不会设置回 nil。
因此,例如,如果您在实时代码中使用 URLSession.DataTaskPublisher
但在某些测试用例中替换 Just
发布者,则测试可能会触发竞争条件。
这是解决此问题的一种方法:跟踪订阅是否已完成。在sink
returns之后检查,在设置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
被销毁时,它会自行取消(如果尚未取消)。