Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Asynchronous callback

Tags:

How do I make asynchronous callbacks in swift? I'm writing a little Framework for my app because it's supposed to run on both, iOS und OS X. So I put the main code that is not device-specific into this framework that also handles requests to my online api. And obviously I also want the app's GUI and therefore my ViewControllers to react as soon as a api request has finished. In Objective-C I've done this by saving the view containing the function that had to be called in an id variable and the function itself in a selector variable. Then I invoked the function using the following code:

SEL selector = callbackMethod; ((void (*)(id, SEL))[callbackViewController methodForSelector:selector])(callbackViewController, selector); 

How can I accomplish this in swift? Or is there a better way of doing this?

I really appreciate all your help!

like image 774
stoeffn Avatar asked Jul 31 '14 09:07

stoeffn


People also ask

Can callbacks be asynchronous?

Callbacks are not asynchronous by nature, but can be used for asynchronous purposes. In this code, you define a function fn , define a function higherOrderFunction that takes a function callback as an argument, and pass fn as a callback to higherOrderFunction .

How does Swift handle async calls?

Async methods call in a function that does not support concurrency. Using async methods in Swift might result in an error like “'async' call in a function that does not support concurrency.” Using the async method using the trailing closure, we create an environment in which we can call asynchronous methods.

What is asynchronous code in Swift?

An asynchronous function in Swift can give up the thread that it's running on, which lets another asynchronous function run on that thread while the first function is blocked. When an asynchronous function resumes, Swift doesn't make any guarantee about which thread that function will run on.

Does Swift have async await?

Swift now supports asynchronous functions — a pattern commonly known as async/await. Discover how the new syntax can make your code easier to read and understand. Learn what happens when a function suspends, and find out how to adapt existing completion handlers to asynchronous functions.


1 Answers

I've shared the pattern that I use for this scenario in the following gist: https://gist.github.com/szehnder/84b0bd6f45a7f3f99306

Basically, I create a singleton DataProvider.swift that setups an AFNetworking client. Then the View Controllers call methods on that DataProvider, each of which is terminated by a closure that I've defined as a typealias called ServiceResponse. This closure returns either a dictionary or an error.

It allows you to very cleanly (imo) call for an async data action from the VC's with a very clear indication of what you want performed when that async response returns.

DataProvider.swift

typealias ServiceResponse = (NSDictionary?, NSError?) -> Void  class DataProvider: NSObject {      var client:AFHTTPRequestOperationManager?     let LOGIN_URL = "/api/v1/login"      class var sharedInstance:DataProvider {         struct Singleton {             static let instance = DataProvider()         }         return Singleton.instance     }      func setupClientWithBaseURLString(urlString:String) {         client = AFHTTPRequestOperationManager(baseURL: NSURL.URLWithString(urlString))         client!.operationQueue = NSOperationQueue.mainQueue()         client!.responseSerializer = AFJSONResponseSerializer()         client!.requestSerializer = AFJSONRequestSerializer()     }      func loginWithEmailPassword(email:String, password:String, onCompletion: ServiceResponse) -> Void {         self.client!.POST(LOGIN_URL, parameters: ["email":email, "password":password] , success: {(operation:AFHTTPRequestOperation!, responseObject:AnyObject!) -> Void in              self.setupClientWithBaseURLString("http://somebaseurl.com")              let responseDict = responseObject as NSDictionary                 // Note: This is where you would serialize the nsdictionary in the responseObject into one of your own model classes (or core data classes)                 onCompletion(responseDict, nil)             }, failure: {(operation: AFHTTPRequestOperation!, error:NSError!) -> Void  in                 onCompletion(nil, error)             })     } } 

MyViewController.swift

import UIKit  class MyViewController: UIViewController {      override func viewDidLoad() {         super.viewDidLoad()          // Do any additional setup after loading the view.     }      override func viewWillAppear(animated: Bool)  {         super.viewWillAppear(animated)         DataProvider.sharedInstance.loginWithEmailPassword(email:"[email protected]", password:"somepassword") { (responseObject:NSDictionary?, error:NSError?) in              if (error) {                 println("Error logging you in!")             } else {                 println("Do something in the view controller in response to successful login!")             }         }     }   } 
like image 197
user871177 Avatar answered Sep 20 '22 17:09

user871177