Nsurlconnection Sendasynchronousrequest Can't Get Variable Out of Closure

NSURLConnection sendAsynchronousRequest can't get variable out of closure

This is calling asynchronous function that is using a completion handler block/closure. So, you need to employ the completion handler pattern in your own code. This consists of changing the method return type to Void and adding a new completionHandler closure that will be called when the asynchronous call is done:

func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) {
let URL = NSURL(string: url)!
let request = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
let bodyData = info
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { response, data, error in
guard data != nil else {
completionHandler(nil, error)
return
}

completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
}
}

Or, since NSURLConnection is now formally deprecated, it might be better to use NSURLSession:

func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) -> NSURLSessionTask {
let URL = NSURL(string: url)!
let request = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
let bodyData = info
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
guard data != nil else {
completionHandler(nil, error)
return
}

completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
}
}
task.resume()

return task
}

And you call it like so:

post(url, info: info) { responseString, error in
guard responseString != nil else {
print(error)
return
}

// use responseString here
}

// but don't try to use response string here ... the above closure will be called
// asynchronously (i.e. later)

Note, to keep this simple, I've employed the trailing closure syntax (see Trailing Closure section of The Swift Programming Language: Closures), but hopefully it illustrates the idea: You cannot immediately return the result of an asynchronous method, so provide a completion handler closure that will be called when the asynchronous method is done.

How do I access variables that are inside closures in Swift?

var dict: NSDictionary! // Declared in the main thread

The closure is then completed asynchronously so the main thread doesn't wait for it, so

println(dict)

is called before the closure has actually finished. If you want to complete another function using dict then you will need to call that function from within the closure, you can move it into the main thread if you like though, you would do this if you are going to be affecting UI.

var dict: NSDictionary!
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response, data, error) in
var jsonError: NSError?
let json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &jsonError) as? NSDictionary
dict = json
//dispatch_async(dispatch_get_main_queue()) { //uncomment for main thread
self.myFunction(dict!)
//} //uncomment for main thread
})

func myFunction(dictionary: NSDictionary) {
println(dictionary)
}

block reference in Swift

In this case self does not have a reference to the block so you would not need to make self weak. But if you did, you would use capture lists as @Stripes mentioned. self would also become an optional in this case.

So something like this:

NSURLConnection.sendAsynchronousRequest(request1, queue: nil) { [weak self] response, data, error in
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
self?.updateDataToPlace(jsonResult)
}

(I've updated your code slightly to be more concise and use trailing closure syntax)

Asynchronous Request not properly updating variables

I've Solved it! using Rob's answer here. basically I need to do all asynchronous activity WITHIN the asynch call and just have everything refresh when complete.

How to use NSURLConnection completionHandler with swift

Like this:

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ response, data, error in /* Your code */ })

Or more verbose variant.

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
/* Your code */
})

Function completes before NSURLSession - dataTaskWithRequest completed

if I understand your question, you can solve this problem at this way
For example:

class func ConnectedToNetwork(completionHandler: ((Status: Bool) -> Void))
{
let url = NSURL(string: "http://google.com")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "HEAD"
request.timeoutInterval = 0.2
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data,response, error) in
let httpResponse = response as! NSHTTPURLResponse
if httpResponse.statusCode == 200
{ completionHandler(Status: true)
return
}
}
task.resume()
}

and then, you can work with this

Checks.ConnectedToNetwork({ Status in dispatch_async(dispatch_get_main_queue())
{
if Status == true
{
//do what you want
}
});

Void Inside of Return function

That's the unchallenged #2 Swift question after unexpected nil found while unwrapping an optional.

The method describes pretty well what is does :

capture still image asynchronously.

You cannot return anything from a method which contains an asynchronous task.

You need a completion block:

func clickPicture(completion:(UIImage?) -> Void) {

guard let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo) else { completion(nil) }

videoConnection.videoOrientation = .portrait
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in

guard let buffer = sampleBuffer else { completion(nil) }

let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let dataProvider = CGDataProvider(data: imageData!)
let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)

let image = UIImage(cgImage: cgImageRef!, scale: 1, orientation: .right)

completion(image)

})
}

and call it this way:

clickPicture { image in 
if unwrappedImage = image {
// do something with unwrappedImage
}
}

How to use completion handler correctly

Here's how to implement it:

func getUserIdFromUsername(username: String, completionHandler: String -> Void) {

let query = PFQuery(className: "_User")
query.whereKey("username", equalTo: username)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
completionHandler(object.objectId!)
}
}
}
}

And here's how to use it:

getUserIdFromUsername("myUser") { id in
doSomethingWithId(id)
}

return string inside block of NSURLConnection - Incompatible block pointer types sending

There are a couple of issues.

  • Naming Conventions

  • Your method getToken:andPassword: should be asynchronous.

  • Improper use of NSOperationQueue (you don't need that)

  • No Content-Type header specified

  • Omitting parameter encoding in the Query component of the URI (x-www-form-urlencoded)

  • Some lack of experience which NSURLConnection:

    Don't use class convenience methods unless you know exactly that your request works with the implemented default behavior (for requests with authentication this is almost always never the case). Please read the official docs

    • sendAsynchronousRequest:queue:completionHandler:
    • URL Loading System Programming Guide

So, for a solution, I would suggest the delegate approach of either NSURLConnection or NSURLSession. See examples and code snippets in the official docs already mentioned above.

You will have to handle an authentication challenge, where you provide the credentials. This also frees you from the error prone and inconvenient need to percent encode the parameters if you would put them into the URL or the body.

You should also use https.



Related Topics



Leave a reply



Submit