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
In Swift, How to Avoid Both Optionals and Nil Object References
Using Multiple Storyboards in iOS
Change the Uitableviewcell Height According to Amount of Text
iOS 8 Rotation Methods Deprecation - Backwards Compatibility
Retrieve Custom Prototype Cell Height from Storyboard
Nscamerausagedescription in iOS 10.0 Runtime Crash
How to Make Uitextview Height Dynamic According to Text Length
Core Data - Failed to Load Optimized Model at Path
Disable iOS8 Quicktype Keyboard Programmatically on Uitextview
Error When Adding Input View to Textfield iOS 8
Insert CSS into Loaded HTML in Uiwebview/Wkwebview
How to Create a Delay in Swift
Use Multiple Font Colors in a Single Label
How to Create Managedobjectcontext Using Swift 3 in Xcode 8
How to Achieve a "Clock Wipe"/ Radial Wipe Effect in iOS
Long Press Gesture on Uicollectionviewcell