Hi! Everyone,
I am using Moya 10.0 + RxSwift + ObjectMapper
and I am trying to called WebService but nothing return it just skip the response part.
Could you guy guide me on how to do this ?
Thank you so much.
This is a code
This is my custom Provider class
public class POINTProvider<T: TargetType> {
public static func rxProvider() -> MoyaProvider<T> {
var plugins = [PluginType]()
plugins.append(AuthPlugin())
//plugins.append(PointBasePlugin())
return MoyaProvider<T>(stubClosure: MoyaProvider<T>.neverStub, plugins: plugins)
}
}
This is when I tried to call webservice
struct Input {
let viewDidAppearTrigger: Driver<Void>
}
let isLoading = ActivityIndicator()
var onRequestPromotion: Driver<Result<PromotionResponse,ServiceError>>!
init(input: Input) {
onRequestPromotion = input.viewDidAppearTrigger
.flatMapLatest({ [unowned self] (_) in
let provider = POINTProvider<PromotionService>.rxProvider()
return provider.rx
.request(.getPromotion)
.asObservable()
.trackActivity(self.isLoading)
.mapServiceObject(PromotionResponse.self)
.flatMap({ (response) in
switch response {
case .success(let response):
return Driver.just(.success(response))
case .failure(let error):
return Driver.just(.failure(error))
}
})
})
}
This is my map class
extension ObservableType where Self.E == Moya.Response {
public func mapServiceObject<T: Mappable>(_ type: T.Type) -> Driver<Result<T, ServiceError>> where T : BaseMappable {
return self.mapObject(type)
.map({ (response: T) -> Result<T, ServiceError> in
if let response = response as? BaseResponse {
if response.isError {
return .failure(response.throwableError)
}
}
return .success(response)
})
.asDriver(onErrorRecover: { (error) in
return Driver.just(.failure(ServiceError.unknownError(fromError: error)))
})
}
}
My quick guess, it's because the provider is deallocated before/while you're doing network request. To fix this, you either need to make the provider a property of the Input struct, or make it available globally(I don't know whether this is a good idea though).
If you're coming from Moya 8/9, this is a change that breaks the old behaviour, which took me some time to realise when migrating my project from Swift 3.2 to Swift 4. You can learn more in #1558
@esam091 .. Thank you for your response.
Yes, I have upgrade from Swift 3.2 to Swift 4 it was working fine like you said in Moya previous version
but after upgrading to this working it stop working.
It like you said it seems like no call was made out and never received response back.
I will try with you solution first and will let you know.
@esam091 .. Its still not working I don't know why do you have any suggestion or what should be modify in my code ?
Thank you.
Can you post your updated code so I can see what's wrong with it?
@esam091 I have tried 2 implementation :
In which first implementation work fine can I can retrieved data.
But in the second implementation when it reached ' .mapServiceObject(PromotionResponse.self)'
and ran into .flatmap it just skip that part, I don't know whether my 'mapServiceObject' is wrong or not.
You can check my 'mapServiceObject' in my first post.
Thank you so much.
First :
public class PromotionViewController: UIViewController {
let promotions = ["try"]
let disposeBag = DisposeBag()
var viewModel: PromotionViewModel!
@IBOutlet weak var tableView: UITableView!
var viewDidAppearTrigger = PublishSubject<Void>()
override public func viewDidLoad() {
super.viewDidLoad()
self.setupView()
let Provider = POINTProvider<PromotionService>.rxProvider()
Provider.rx.request(.getPromotion)
.asObservable()
.mapObject(PromotionResponse.self)
.subscribe { event -> Void in
switch event {
case .next(let repos):
print(repos.dictionaryRepresentation())
break
//self.repos = repos
case .error(let error):
print(error)
default: break
}
}.disposed(by: disposeBag)
```
Second :
class PromotionViewModel {
struct Input {
let viewDidAppearTrigger: Driver<Void>
}
let isLoading = ActivityIndicator()
var onRequestPromotion: Driver<Result<PromotionResponse,ServiceError>>!
init(input: Input) {
onRequestPromotion = input.viewDidAppearTrigger
.flatMapLatest({ [unowned self] (_) in
let provider = POINTProvider<PromotionService>.rxProvider()
return provider.rx
.request(.getPromotion)
.asObservable()
.trackActivity(self.isLoading)
.mapServiceObject(PromotionResponse.self)
.flatMap({ (response) in
switch response {
case .success(let response):
//return response
return Driver.just(.success(response))
case .failure(let error):
return Driver.just(.failure(error))
}
})
})
}
This is my PromotionResponse class
public class PromotionResponse: BaseResponse {
private struct SerializationKeys {
static let promotions = "promotions"
}
// MARK: Properties
public var promotions: [Promotions]?
public required init?(map: Map){
super.init(map: map)
}
public override func mapping(map: Map) {
super.mapping(map: map)
promotions <- map[SerializationKeys.promotions]
}
public override func dictionaryRepresentation() -> [String: Any] {
var dictionary: [String: Any] = [:]
if let value = promotions { dictionary[SerializationKeys.promotions] = value.map { $0.dictionaryRepresentation() } }
return dictionary
}
}
```
@BuildBuilt As @esam091 suggested your provider is being deallocated before the request completes. You need to make it a property of PromotionViewController or something. You need to store it as a property and tie it to the lifetime of the controller.
@SD10 .. Thank for your response.
Could you please suggest me on how to do it ?
I have tried various way but not working yet.
@BuildBuilt when you initialize the provider inside the init assign it to a property of the object before making the request
Sent with GitHawk
Simply do it like this
public class PromotionViewController: UIViewController {
// Retain the provider here, network requests will work as long as the view controller is still alive
let provider = POINTProvider<PromotionService>.rxProvider()
func viewDidLoad() {
provider.rx.request(...).disposed(by: disposeBag)
}
}
In your last implementation, you stored the provider in a local variable in viewDidLoad method, which will be deallocated when viewDidLoad finishes executing.
@esam091 @SD10 .. Thank you for your suggestion.
I have tried as you suggested and it seems to be working fine now.
Thank you so much for your help and I will test it again and let you know whether it works fine or not.
Really thank you both.
馃槅
Happy you got this figured out. Open a new issue if you get stuck on anything else!
Most helpful comment
Simply do it like this
In your last implementation, you stored the provider in a local variable in viewDidLoad method, which will be deallocated when viewDidLoad finishes executing.