Reputation: 1
Hi So i am trying to wrap an async network request with Combine's Future/Promise.
my code goes something like that:
enum State {
case initial
case loading
case success(movies: [Movie])
case error(message: String)
}
protocol ViewModelProtocol {
var statePublisher: AnyPublisher<State, Never> { get }
func load(genreId: String)
}
class ViewModel: ViewModelProtocol {
var remoteDataSource = RemoteDataSource()
@Published state: State = .initial
var statePublisher: AnyPublisher<State, Never> { $state.eraseToAnyPubliher() }
public func load(genreId: String) {
self.state = .loading
self.getMovies(for: genreId)
.sink { [weak self] (moveis) in
guard let self = self else { return }
if let movies = movies {
self.state = .success(movies: movies)
} else {
self.state = .error(message: "failed to load movies")
}
}
}
func getMovies(for genreId: String) -> AnyPublisher<[Movie]?, Never> {
Future { promise in
self.remoteDataSource.getMovies(for: genreId) { (result) in
switch result {
case .success(let movies): promise(.success(movies))
case .failure: promise(.success(nil))
}
}
}.eraseToAnyPublisher()
}
}
I was trying to see if there are any memory leaks and found that there is a reference to the Future that is not being deallocated same as here: Combine Future Publisher is not getting deallocated
Upvotes: 0
Views: 521
Reputation: 16327
You are strongly capturing self inside of your escaping Future init (just capture remoteDataSource
). It doesn't seem to me like this should cause a memory leak. As the link you put in the question suggests Future does not behave like most other publishers; it does work as soon as you create it and not when you subscribe. It also memoizes and shares its results. I strongly suggest that you do no use this behind an AnyPublisher because its very non obvious to the caller that this thing is backed by a Future and that it will start work immediately. I would use URLSession.shared.dataTaskPublisher instead and then you get a regular publisher and you don't need the completion handler or the Future. Otherwise wrap the Future in a Deferred so you don't get the eager evaluation.
Upvotes: 2