简体   繁体   中英

Using a Swift closure to capture a variable

I have this bit of code and it obviously errors out because when I use FOO in the return statement it's outside of the scope of the function. I know (I think I know) I need to use a closure to capture the variable but I can't figure out how to do that. Using Alamofire & SwiftyJSON. Any help would be great! Thanks!

  func getPlayerID(named: String) -> String {

    Alamofire.request(.GET, "URL", headers: headers)
        .responseJSON { response in


        let json = JSON.self(response.result.value!)

        for var index = 0; index < json.count; index++ {
            if json[index]["Name"].stringValue == named {
                var FOO = json[index]["FOO"].stringValue
            } // If Statement End
        } // For Loop End
    } // Alamofire Request End

     // Return Statement for getPLayerID Function

        return FOO

} // getPlayerID Function End
} // Player Struct End

The basic idea is that getPlayerID should not return anything, but rather should just have a parameter which is a closure, and once you retrieve the value you want to "return", you call the closure using that value as a parameter.

But, I'd suggest all sorts of other refinements here:

  • Build an array of the strings and return that
  • Check to see if result is a .Failure because you have no control over what various server/network issues may arise
  • Change the closure to detect and report errors

But hopefully this illustrates the basic idea:

Personally, I'd (a) make the String parameter to the completionHandler optional; (b) add another optional error parameter; and (c) add error handling to the getPlayerID :

func getPlayerID(completionHandler: ([String]?, ErrorType?) -> Void) {
    Alamofire.request(.GET, "URL", headers: headers)
        .responseJSON { request, response, result in
            switch (result) {
            case .Success(let value):
                let json = JSON.self(value)

                // variable to hold all of the results

                var strings = [String]()   

                // populate the array of strings

                for var index = 0; index < json.count; index++ {
                    if json[index]["Name"].stringValue == named {
                        strings.append(json[index]["FOO"].stringValue)
                    }
                }

                // call the completion handler with the strings

                completionHandler(strings, nil)
            case .Failure(_, let error):
                completionHandler(nil, error)
            }
    }
}

And then, when you want to call it:

getPlayerID() { strings, error in
    // use `strings` here
}

// but not here

If you make an asynchronous request you can not return a value received in response in the same function cause it needs time for request to be sent over network to the server and back. The best way to solve this out is to add callback parameter to your function instead of return value.

func getPlayerID(named: String, callback:(foo:String)->()) {

    Alamofire.request(.GET, "URL", headers: headers)
        .responseJSON { response in


            let json = JSON.self(response.result.value!)

            for var index = 0; index < json.count; index++ {
                if json[index]["Name"].stringValue == named {
                    var FOO = json[index]["FOO"].stringValue
                    callback(foo: FOO)   // you fire callback here..
                } // If Statement End
            } // For Loop End
    } // Alamofire Request End

} // getPlayerID Function End

Callback is a block object that will be fired when your response will be received. So if response is not coming (for example, internet connection went down) callback will never fired. Example how to use this:

self.getPlayerID("ototo") { (foo) -> () in
    print("foo received = \(foo)")
}

Also there is a time span between sending the request and receiving the response. So it is a good practice to add UIActivityIndicatorView in UI of your app until response is arrived (and handle timeout if internet connection suddenly went down).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM