swift 3 completion handler to return string

2019-09-19 20:25发布

问题:

I am new at swift and got problem with getting string from function, I am trying to use completion handler, but something is wrong, could you help me?

After adding [String : String] to func, I cant get rezult, I want to get response and print it. Error: Cannot convert return expresion of type () to return type [String : String]

Requests:

public func login(userName: String, password: String) -> [String : String]{

let loginrequest = JsonRequests.loginRequest(userName: userName, password: password)
return makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in

   print("\(JSON)")

})

}


private func makeWebServiceCall (urlAddress: String, requestMethod: HTTPMethod, params:[String:Any], completion: @escaping (_ JSON : Any) -> ()) {


    Alamofire.request(urlAddress, method: requestMethod, parameters: params, encoding: JSONEncoding.default).responseJSON { response in

        switch response.result {
        case .success:
            if let jsonData = response.result.value {
                completion(jsonData)
            }
        case .failure(let error):
            if let data = response.data {
                let json = String(data: data, encoding: String.Encoding.utf8)
                print("Failure Response: \(json)")

            }

Calling function:

let retur = Json()
    let rezultatas = retur.login(userName: "root", password: "admin01")

    print(rezultatas)

Errors: enter image description here

回答1:

Welcome to Swift :)

You are mixing synchronous and asynchronous code together.

When you call login you expect it to return an answer straight away of type [String : String].

But in your login method you then do a network call which can not return straight away...which is why the call to Alamofire.requesttakes a completion block as a parameter.

So...you need to change your login method so it:

  1. does not return anything straight away (it can not do so...logging in requires us doing a network call remember)
  2. takes a completion block to invoke once login has succeeded.

This can be done like so:

public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ())

Here we have a function that takes a userName of type String, a password of type String and a loginCompletion of type function that again takes a [String : String] dictionary as a parameter. Notice that the method does not return anything.

Now you can call your makeWebServiceCall almost as before:

let loginrequest = JsonRequests.loginRequest(userName: userName, password: password)
makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in
   //Now we are ready, the login call has returned some data to you. 

   //You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so:
   loginCompletion(yourConvertedDictionaryHere)
})

Here is the new login method in its completeness:

public func login(userName: String, password: String, loginCompletion: @escaping ([String : String]) -> ()) {
    let loginrequest = JsonRequests.loginRequest(userName: userName, password: password)
    makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in
       //Now we are ready, the login call has returned some data to you. 

       //You have an attribute named JSON of type Any, which you need to convert to [String : String], and then you can call loginCompletion with that, like so:
       loginCompletion(yourConvertedDictionaryHere)
    })
}

And then you call your login method like so:

retur.login(userName: "root", password: "admin01") { stringDictionary: [String : String] in
    //here you have your stringDictionary which you can use as pleased
}

Hope that helps you.



回答2:

Make a function definition like this

private func makeWebServiceCall (urlAddress: String, requestMethod: String, params:[String:Any], completion: @escaping (_ JSON : Any) -> ()) {

completion("Make a service call")

}

Make function calling like this

makeWebServiceCall(urlAddress: "", requestMethod: "", params: ["Key" : "value"], completion: { (JSON : Any) in

            print("\(JSON)")

        })

I have changed DataType of Parameters due to simplicity. Also you can pass any type of data in completion("Make a service call"). Hopefully this will help you.