So I'm using RxSwift
and has a function
that looks like this:
private func setAndVerifyTestmode(isOn: Bool) {
parameterService.setTestMode(value: isOn)
.flatMap { _ in self.parameterService.requestTestMode() }
.subscribe( { [weak self] _ in
//do stuff })
.disposed(by: disposeBag)
}
I noticed that I had forgotten to use [weak self]
in the .flatMap
so I added it like this:
private func setAndVerifyTestmode(isOn: Bool) {
parameterService.setTestMode(value: isOn)
.flatMap { [weak self] (_: Int?) in
guard let self = self else { return .just(nil) }
self.parameterService.requestTestMode() }
.subscribe( { [weak self] _ in
//do stuff })
.disposed(by: disposeBag)
}
But then it gave me an error: Generic parameter Result could not be infered
I couldn't get around it so I tried using a nested function
instead of the closure
, ending up with this:
private func setAndVerifyTestMode(isOn: Bool) {
func requestTestMode(_: Int?) -> Single<Int?> {
parameterService.requestTestMode()
}
parameterService.setTestMode(value: isOn)
.flatMap(requestTestMode(_:))
.subscribe( { [weak self] _ in
//do stuff })
.disposed(by: disposeBag)
}
Great, the compiler was happy and it works. And in my world this takes care of the memory leak issues since I'm no longer using a closure
requiring a reference to self
. But, a collegue of mine told me that this is the exact same thing as not using [weak self]
in a closure
; and that you are still subjected to memory leaks
using a nested function
. I can't really see that they are the same thing since there isn't even a reference to self
anymore.
Anyway, the question I have is: Do I get around the issue with memory leaks
, self
and [weak self]
using the nested function above, or is my collegue right: it's the same thing; there is no gain to what I did?
But, a collegue of mine told me that this is the exact same thing as not using [weak self] in a closure; and that you are still subjected to memory leaks using a nested function.
Your colleague is right. (This surprised me.)
Fortunately, there are easier ways:
The most obvious: .flatMap { [parameterService] _ in parameterService.requestTestMode() }
By capturing parameterService directly instead of indirectly through self, you avoid capture of self.
Another option: .flatMap { [weak self] _ in self?.parameterService.requestTestMode() ?? .just(0) }
The value to emit is problematic because you used a Single so you have to emit something. If you had used a Maybe or Observable, you could have just used .empty()
Like this: .asMaybe().flatMap { [weak self] _ in self?.parameterService.requestTestMode().asMaybe() ?? .empty() }
Lastly you could use a free function (one that is not bound to any class or struct) that is curried:
func requestTestMode(parameterService: ParameterService) -> (Int?) -> Single<Int?> {
{ _ in parameterService.requestTestMode() }
}
Which could be used like: .flatMap(requestTestMode(parameterService: parameterService))
And that is effectively the same as the first option I gave above.