Moya 8.0.0
This is probably a stupid question but I can't find anything anywhere about this issue. Please note that I'm relatively new to Swift.
I have Moya concepts / RxSwift all working without any issue outside of this use case.
I'm using a singleton class to manage a target for simplicity reasons and keeping consistency with another app.
Something very basic.
class KodiManager {
private static let sharedInstance: KodiManager = KodiManager()
static func getInstance() -> KodiManager {
return sharedInstance
}
.... Lots of irrelevant code about the issue....
public func kodiHostHaveAddon(host: String, port: Int, login: String, password: String, addonId: String) -> Observable<Bool> {
let provider = RxMoyaProvider<KodiProvider>(
endpointClosure: getEndpointForKodiHost(host: host, port: port, login: login, password: password),
manager: alamoManager)
return provider.request(.addonsGetDetails(addonId))
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.filterSuccessfulStatusCodes()
.map(to: AddonDetailsResponse.self)
.flatMap {
(response: AddonDetailsResponse) -> Observable<Bool> in
if (response.addon?.addonId?.isEmpty ?? true) {
return Observable.just(false)
}
return Observable.just(addonId.lowercased() == response.addon?.addonId?.lowercased())
}
}
}
If I call this
KodiManager.getInstance().kodiHostHaveAddon(host: kodiHost.ip, port: kodiHost.httpPort, login: "", password: "", addonId: "xxxxx").subscribe()
Then the request is never fired.
If I store the provider as a local variable of the singleton then it works (See below). But of course it is problematic when calling 3 times the same function at the same time in a .zip for example.
class KodiManager {
private var kodiAddonProvider: RxMoyaProvider<KodiProvider>? = nil
public func kodiHostHaveAddon(host: String, port: Int, login: String, password: String, addonId: String) -> Observable<Bool> {
kodiAddonProvider = RxMoyaProvider<KodiProvider>(
endpointClosure: getEndpointForKodiHost(host: host, port: port, login: login, password: password),
manager: alamoManager)
return kodiAddonProvider.request(.addonsGetDetails(addonId))
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.filterSuccessfulStatusCodes()
.map(to: AddonDetailsResponse.self)
.flatMap {
(response: AddonDetailsResponse) -> Observable<Bool> in
if (response.addon?.addonId?.isEmpty ?? true) {
return Observable.just(false)
}
return Observable.just(addonId.lowercased() == response.addon?.addonId?.lowercased())
}
}
}
This does not happens if I return a simple Observable from the singleton.
I'm pretty sure this is something known, I read things about escaping but can't find how / where it would apply in that case.
Any help would be highly appreciated.
Hey @Tolriq, this is not a stupid question at all. The behavior you are experiencing is not very well defined. The basic issue is that your RxMoyaProvider is being deallocated before the request can be processed. This is because it is a local variable that goes out of scope and the Observable it produces does not retain the provider strongly. This is related to #844 and the behavior that was changed in #905.
Since the new behavior hasn't been released yet, try pointing your dependency manager at the master branch to see if it behaves how you are expecting it to.
Also, storing a provider locally may not be a bad idea regardless. But instead of dynamically creating a new one each time you call kodiHostHaveAddon, can you instead just create a single provider and use it in multiple requests?
@scottrhoyt Thanks for confirming I'm not mad :)
About storing the provider, this is what I do for the normal behavior of this singleton, then use a subject to push updates and things to listeners, classic Rx things.
But this is when already connected to a known host.
This function and another are made for discovering of the hosts and testing. So it's more temporary things I'd like to avoid to increase complexity of client to avoid requesting a provider then calling the function.
Not sure #905 would fix the issue, it sounds like I would at least receive the error but I'll try as soon as I can.
Is there a workaround to force the provider to not be deallocated ?
I use cocoapods, if you have a quick hint at how to migrate to master with it :)
pod 'Moya', :git => 'https://github.com/Moya/Moya.git', :branch => 'master'
Thanks will test all that tomorrow.
Ok so tested and yes Master does behave more normally for that use case.
I have not tested long time provider retention but at least for the time between the return of the func and the call it now always correctly fire the request and return a result.
Thanks for the help and the working solution :)
Is there an estimate about a public release date ?
Glad to hear it worked, @Tolriq! No release date set, but given that this issue has come up a couple of times, I think this could warrant 8.0.1, what do you think @Moya/contributors?
@scottrhoyt 8.0.1 makes sense to me. Should we open an issue to discuss?
Yeah, I'd say go for it @pedrovereza.
Closing this @Tolriq. Let us know if you have any other issues.