I have a sink that needs to be canceled as soon as I receive the first value. I don't care about future values, just the first one published. Because without storing the AnyCancelable
created by the sink, the garbage collector will delete the sink, I must store it. At the same time, I must also clean it up after the sink has completed, otherwise, I will have a memory leak.
I built one using a UUID → AnyCancelable map, but I am worried that this is more complex than it should be; is there another way of doing this? What's recommended by 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)
}
If you just need to keep it alive until the sink is called once, you can just create a temporary variable
var cancellable: AnyCancellable?
cancellable = $locationState.sink { locationState in
if let locationState = locationState {
invokeCallbackWithLocationState(locationState)
}
cancellable = nil
}
This will retain the AnyCancellable
long enough (because the closure retains the reference)