I have this custom implementation of Alamofire
:
protocol HTTPProtocol: class {
typealias RequestType
typealias RespondType
func doRequest(requestData: RequestType) -> Self
func completionHandler(block:(Result<RespondType, NSError>) -> Void) -> Self
}
//example of a request:
locationInfo
//Make a request
.doRequest(HTTPLocationInfo.RequestType(coordinate: $0))
//Call back when request finished
.completionHandler { result in
switch result {
case .Success(let info): self.locationInfoRequestSuccess(info)
case .Failure(let error): self.locationInfoRequestFailed(error)
}
}
I want to apply MVVM and RxSwift into my project. However, I can't find a proper way to do this.
What I want to achieve is a ViewModel
and a ViewController
that can do these things:
class ViewController {
func googleMapDelegate(mapMoveToCoordinate: CLLocationCoordinate2D) {
// Step 1: set new value on `viewModel.newCoordinate` and make a request
}
func handleViewModelCallBack(resultParam: ...*something*) {
// Step 3: subscribeOn `viewModel.locationInfoResult` and do things.
}
}
class ViewModel {
//Result if a wrapper object of Alamofire.
typealias LocationInfoResult = (Result<LocationInfo.Respond, NSError>) -> Void
let newCoordinate = Variable<CLLocationCoordinate2D>(kInvalidCoordinate)
let locationInfoResult: Observable<LocationInfoResult>
init() {
// Step 2: on newCoordinate change, from step 1, request Location Info
// I could not find a solution at this step
// how to make a `completionHandler` set its result on `locationInfoResult`
}
}
Any help is deeply appreciated. Thank you.
You can use RxAlamofire as @Gus said in the comment. But if you are using any library that doesn't support Rx extensions by default you may need to do the conversion by hand.
So for the above code snippet, you can create an observable from the callback handler you had implemented
func getResultsObservable() -> Observable<Result> {
return Observable.create{ (observer) -> Disposable in
locationInfo
//Make a request
.doRequest( .... )
//Call back when request finished
.completionHandler { result in
switch result {
case .Success(let info): observer.on(Event.Next(info))
case .Failure(let error): observer.on(Event.Error(NetworkError()))
}
}
return Disposables.create {
// You can do some cleaning here
}
}
}
Callback handlers are implementation to observer pattern, so mapping it to a custom Observable is a straight forward operation.
A good practice is to cancel the network request in case of disposing, for example this is a complete disposable Post request:
return Observable<Result>.create { (observer) -> Disposable in
let requestReference = Alamofire.request("request url",
method: .post,
parameters: ["par1" : val1, "par2" : val2])
.validate()
.responseJSON { (response) in
switch response.result{
case .success:
observer.onNext(response.map{...})
observer.onCompleted()
case .failure:
observer.onError(NetworkError(message: response.error!.localizedDescription))
}
}
return Disposables.create(with: {
requestReference.cancel()
})
Note: before swift 3 Disposables.create()
is replaced with NopDisposable.instance