0

I made a synchron function to sign in a user, but the http request inside the function is asyc, so the parent function returns false before the async part happens. I know that I somehow have to turn signingInExtension an async function with completion handling, and then call it differently from the viewDidLoad function, I just cannot figure out the syntax.

Also the http request comes with a completionHandler, but I do not understand how I can modify it to pass its return value up to where it is called.

 override func viewDidLoad() {
    signedIn = signingInExtension()
  }

  func signingInExtension() -> Bool {
    if (self.singleUseIdentityToken != nil) {
      if (!tokenExpired(t: self.singleUseIdentityToken)) {
        let parameters = [
          "method": "single-use-identity-token",
          "token": self.singleUseIdentityToken!
        ] as [String : Any]
        let url = URL(string: self.endpoint + "/auth/signin")!
        let session = URLSession.shared
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        do {
          request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
        } catch let error {
          print(error.localizedDescription)
        }
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in

          guard error == nil else {
            return
          }

          guard let data = data else {
            return
          }

          do {
            if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
              if (json["token"] == nil) {
                return
              } else {
                print(json["token"] as! String)
                // store token in file
                // here I would like signingInExtension to return true
                // but it already returned false because I am not handling async correctly
              }
            }
          } catch let error {
            print(error.localizedDescription)
          }
        })
        task.resume()
      }
    }
    return false // this happens before task
  }

How can I from within the http tasks completion handler return either true or false all the way out to where I call signingInExtension ?

Rasmus Puls
  • 3,009
  • 7
  • 21
  • 58

1 Answers1

1

You need to use a completion handler to return from signingInExtension() like this:

func signingInExtension (completion: @escaping (Bool) -> Void)

And somewhere in this method, wherever you want to "return" whether or not the login was successful you would do something like this.

completion(true) // or false, or a boolean variable or whatever you need it to return

To get the return value, you would do something like this.

signingInExtension () { (success)
    self.signedIn = success
}

Hope this makes sense.

adeiji
  • 550
  • 1
  • 3
  • 13