Moya: What should I do in Moya 10.0 ?

Created on 1 Mar 2018  路  11Comments  路  Source: Moya/Moya

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)))
            })
    }

}
question rxmoya

Most helpful comment

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.

All 11 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JoeFerrucci picture JoeFerrucci  路  3Comments

fenixsolorzano picture fenixsolorzano  路  3Comments

fenixsolorzano picture fenixsolorzano  路  3Comments

JianweiWangs picture JianweiWangs  路  3Comments

syq7970 picture syq7970  路  3Comments