如何在 Swift Combine Sink 收到至少一个值后停止存储 AnyCancellable?
How to stop storing AnyCancellable after Swift Combine Sink has received at least one value?
我有一个接收器需要在收到第一个值后立即取消。我不关心未来的价值,只关心第一个发布的价值。因为不存储sink创建的AnyCancelable
,垃圾回收器会删除sink,我必须存储它。同时我也必须在sink完成后进行清理,否则我会内存泄漏。
我使用 UUID → AnyCancelable 映射构建了一个,但我担心这比应该的更复杂;还有另一种方法吗? Combine 推荐什么?
@Published var locationState: (location: CLLocation?, error: Error?)?
var requestLocationSinks: [String: AnyCancellable] = [:]
// 1. Generate ID to uniquely identify the current sink.
let sinkID = UUID().uuidString
// 2. Start the sink and store it in our ID → AnyCancellable dictionary.
requestLocationSinks[sinkID] = $locationState.sink { locationState in
if let locationState = locationState {
invokeCallbackWithLocationState(locationState)
}
// 3. Remove the stored AnyCancellable as soon as we received our first value!
self.requestLocationSinks.removeValue(forKey: sinkID)
}
如果你只需要让它一直存活到sink被调用一次,你可以只创建一个临时变量
var cancellable: AnyCancellable?
cancellable = $locationState.sink { locationState in
if let locationState = locationState {
invokeCallbackWithLocationState(locationState)
}
cancellable = nil
}
这将保留 AnyCancellable
足够长的时间(因为闭包保留了引用)
如果您只对上游的第一个元素感兴趣,您可以使用运算符 .first()
或运算符 .prefix(1)
。他们是平等的。使用 .prefix(n)
您可以定义传递的上游元素的数量。
myPublisher
.first()
.sink( ... )
or
myPublisher
.prefix(1 or n)
.sink( ... )
请注意,上面的两个运算符会导致 .finished
完成。这意味着订阅将在操作后被删除。
publisher is triggered -> receiveValue -> receiveCompletion (finished) -> subscription is deleted
如果您使用 AnyCancellable
并想删除您的订阅,您应该使用 AnyCancellable
的 .cancel()
功能。
var cancellable: AnyCancellable?
cancellable = myPublisher
.sink(receiveValue: { value in
// Your logic.
cancellable.cancel()
})
我想在您的情况下,运算符 .first()
正是您所需要的。
我有一个接收器需要在收到第一个值后立即取消。我不关心未来的价值,只关心第一个发布的价值。因为不存储sink创建的AnyCancelable
,垃圾回收器会删除sink,我必须存储它。同时我也必须在sink完成后进行清理,否则我会内存泄漏。
我使用 UUID → AnyCancelable 映射构建了一个,但我担心这比应该的更复杂;还有另一种方法吗? Combine 推荐什么?
@Published var locationState: (location: CLLocation?, error: Error?)?
var requestLocationSinks: [String: AnyCancellable] = [:]
// 1. Generate ID to uniquely identify the current sink.
let sinkID = UUID().uuidString
// 2. Start the sink and store it in our ID → AnyCancellable dictionary.
requestLocationSinks[sinkID] = $locationState.sink { locationState in
if let locationState = locationState {
invokeCallbackWithLocationState(locationState)
}
// 3. Remove the stored AnyCancellable as soon as we received our first value!
self.requestLocationSinks.removeValue(forKey: sinkID)
}
如果你只需要让它一直存活到sink被调用一次,你可以只创建一个临时变量
var cancellable: AnyCancellable?
cancellable = $locationState.sink { locationState in
if let locationState = locationState {
invokeCallbackWithLocationState(locationState)
}
cancellable = nil
}
这将保留 AnyCancellable
足够长的时间(因为闭包保留了引用)
如果您只对上游的第一个元素感兴趣,您可以使用运算符 .first()
或运算符 .prefix(1)
。他们是平等的。使用 .prefix(n)
您可以定义传递的上游元素的数量。
myPublisher
.first()
.sink( ... )
or
myPublisher
.prefix(1 or n)
.sink( ... )
请注意,上面的两个运算符会导致 .finished
完成。这意味着订阅将在操作后被删除。
publisher is triggered -> receiveValue -> receiveCompletion (finished) -> subscription is deleted
如果您使用 AnyCancellable
并想删除您的订阅,您应该使用 AnyCancellable
的 .cancel()
功能。
var cancellable: AnyCancellable?
cancellable = myPublisher
.sink(receiveValue: { value in
// Your logic.
cancellable.cancel()
})
我想在您的情况下,运算符 .first()
正是您所需要的。