Search code examples
iosswiftalamofirepromisekit

Swift 4 - Call nests with PromiseKit


Good morning everyone!

I'm doing an app with Swift 4.2 with Xcode10 and calls I manage with Alomofire together with PromiseKit.

At one point I need to load a screen at the beginning of the app with the terms of use, but only if they have updated it. And if the version has changed, that same call has the URL with the new endpoint. That endpoint contains the text to be displayed.Therefore, in that last case. We would have to make two calls.

Then I explain what I want to do:

  • To know if they have updated the version number I make a first call and check with the last one that I have saved in the device (NSUsserDefaults).The first call returns the following:

    { "legal_version": "1", "legal_URL": "http://statics.....html" }

  • If it's the same version, I do not show the screen.

  • If the version has changed, I want to make a second call (with the URL that carries the answer of that first call "legal_URL")

he problem is that I do not know how to make that double call blocking. So do not load the main screen without checking the version number. And without knowing if I have to show or not the screen of legal terms again. And all this is PromiseKit and nested calls.

Many thanks, for your help.

[Code updated]

let legalWarningRepository = LegalWarningRepository()
        firstly {
            legalWarningRepository.get(endpoint: "http://myserver.com/version")
            }.then { json in
                if let remoteVersion = json["version"] as? String, let 
                    legalUrl = json["legal_URL"] as? String, 
                    remoteVersion != localVersion {
                        return legalWarningRepository.get(endpoint: legalUrl)
            }
        }.done { json in
            if json == nil {
                // display main screen
            }
            else {
                // display legal terms
            }
        }.catch { err in
            print(err)
    }

And inside "legalWarningViewController" I have the get method that you have passed me:

func get(endpoint: String) -> Promise<[String: Any]> {
  return Promise { seal in
    Alamofire.request(endpoint)
      .validate()
      .responseJSON { response in
        switch response.result {
        case .success(let json):
          guard let json = json  as? [String: Any] else {
            return seal.reject(AFError.responseValidationFailed(reason: 
.dataFileNil))
          }
          seal.fulfill(json)
          case .failure(let error):
            seal.reject(error)
          }
       }
  }
}

Solution

  • On your first screen you can display an activity indicator while waiting for responses. When you have your responses you can display the appropriate view then.

    In order to keep things simple you can create a generic method that "promisify" the Alamofire call:

    func get(endpoint: String) -> Promise<[String: Any]> {
      return Promise { seal in
        Alamofire.request(endpoint)
          .validate()
          .responseJSON { response in
            switch response.result {
            case .success(let json):
              guard let json = json  as? [String: Any] else {
                return seal.reject(AFError.responseValidationFailed(reason: .dataFileNil))
              }
              seal.fulfill(json)
              case .failure(let error):
                seal.reject(error)
              }
           }
      }
    }
    

    Then in your the viewDidLoad or viewWillAppear of your home screen you can do this kind of logic:

    firstly {
      get(endpoint: "http://myserver.com/version")
    }.then { json in
      if let remoteVersion = json["version"] as? String, let legalUrl = json["legal_URL"] as? String, remoteVersion != localVersion {
        return get(endpoint: legalUrl)
      }
    }.done { json in
      if json == nil {
        // display main screen
      }
      else {
        // display legal terms
      }
    }.catch { err in
       print(error.localizedDescription)
    }
    

    In your case a single call may be possible if you display the legal term in a WKWebView.

    firstly {
      get(endpoint: "http://myserver.com/version")
    }.done { json in
      if let remoteVersion = json["version"] as? String, let legalUrl = json["legal_URL"] as? String, remoteVersion != localVersion {
        // display legal terms in a web view
      }
      // display main screen
    }.catch { err in
       print(error.localizedDescription)
    }