Getting Data Out of Completionhandler in Swift in Nsurlconnection

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 */
})

How to declare this method in swift with a completion block?

func downloadImageWithURL(url: NSURL, completionBlock: (succeeded: Bool, image: UIImage?) -> ()) {
let request = NSMutableURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) in
if error == nil {
let image = UIImage(data: data!)
completionBlock(succeeded: true, image: image!)
} else {
completionBlock(succeeded: false, image: nil)
}
}
}

How to get data to return from NSURLSessionDataTask in Swift

With the help and suggestion taken from Abizern I finally managed how to write up this block or closure if you want.

So what worked for me in the end:

The GetHomeData function I changed as follows:

private let siteContent:String = "http://www.imoc.co.nz/MobileApp/HomeContent"
// I changed the signiture from my original question
func GetHomeData(completionHandler: ((NSDictionary!) -> Void)?)
{
var url : NSURL! = NSURL(string:siteContent)
var request: NSURLRequest = NSURLRequest(URL:url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)

let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil

let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary!

// then on complete I call the completionHandler...
completionHandler?(jsonResult?);
});
task.resume()
}

Then I call the function like this:

/*Call to go get home page content*/
func SetHomeContent()
{
homeModel.GetHomeData(self.resultHandler)
}

func resultHandler(jsonResult:NSDictionary!)
{
let siteContent = jsonResult.objectForKey("SiteContent") as NSDictionary
let paraOne = siteContent.objectForKey("HomePageParagraphOne") as String
}

How to use completionHandler Closure with return in Swift?

func getSomething(callback: (Array<AnyObject>) -> ()) {
var dataTask = NSURLSessionDataTask()
dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
if (error == nil) {
var callbackArray = Array<MyObject>()
let responseDict = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
let response = responseDict.objectForKey("response_key") as NSDictionary
let array = response.objectForKey("array_key") as NSArray

for item: AnyObject in array {
var arrayItem = MyObject(dict: item as NSDictionary)
callbackArray.append(arrayItem)
}

callback(callbackArray)
} else {
// handle an error
}
}
dataTask.resume()
}

Then you could do something like:

getSomething() { (response) in
if let responseArray = response as? Array<MyObject> {
self.somethings = responseArray
}
}

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.

Get the data from NSURLSession DownloadTaskWithRequest from completion handler

When using download tasks, generally one would simply use the location provided by the completionHandler of the download task to simply move the file from its temporary location to a final location of your choosing (e.g. to the Documents or Cache folder) using NSFileManager.

let task = NSURLSession.sharedSession().downloadTaskWithURL(url) { location, response, error in
guard location != nil && error == nil else {
print(error)
return
}

let fileManager = NSFileManager.defaultManager()
let documents = try! fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let fileURL = documents.URLByAppendingPathComponent("test.jpg")
do {
try fileManager.moveItemAtURL(location!, toURL: fileURL)
} catch {
print(error)
}
}
task.resume()

You certainly could also load the object into a NSData using contentsOfURL. Yes, it works with local resources. And, no, it won't make another request ... if you look at the URL it is a file URL in your local file system. But you lose much of the memory savings of download tasks that way, so you might use a data task if you really wanted to get it into a NSData. But if you wanted to move it to persistent storage, the above pattern probably makes sense, avoiding using a NSData object altogether.



Related Topics



Leave a reply



Submit