Muhammad Umar Muhammad Umar - 1 year ago 171
Objective-C Question

Conversion of Block with callback in Objective C to closure in Swift

I have following callback in block in Objective C

typedef void (^COMPLETION_BLOCK)(NSString *response, NSError *errorString);

+ (void)responseFromURL:(NSURL *)url completionBlock:(COMPLETION_BLOCK)completionBlock
__block NSError *error = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSString *response = [NSString stringWithContentsOfURL:url

dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(response, error);

Here is how i call it in Objective C

[Utilities responseFromURL:NSURL URLWithString:@""] completionBlock:^(NSString *response, NSError *errorString)


I have tried converting this in Clousers in swift
here is the code

class Utilities
typealias COMPLETION_BLOCK = ( response : NSString, error : NSError) -> ()

func responseFromURL(url: NSURL , completionBlock:COMPLETION_BLOCK)
var e : NSError?;

dispatch_async(dispatch_get_global_queue(priority, 0))
var content:NSString? = NSString(contentsOfURL: url,
encoding: NSUTF8StringEncoding,
error: &e)

completionBlock(response: content!,error: e!);

I am not sure if this is correct conversion. Secondly how am i suppose to call the block in swift?

var urlString = String(format: BASE_URL + "%d", categoryType);
var url = NSURL(string :urlString);

Answer Source

You are almost there. You don't need the typealias as you can specify the completionBlock in the function definition.

One thing that would cause you problems is the forced unwrapping of content & e one of which is going to be nil.

Here is my version of your function:

func responseFromURL(url : NSURL, completionBlock : (response : String?, error : NSError?) -> Void) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        var error : NSError? = nil
        let response = String(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &error)

        dispatch_async(dispatch_get_main_queue()) {
            completionBlock(response: response, error: error)

And to call it:

responseFromURL(myURL) { (response, error) in
    if error != nil {
        // handle error
    else if response != nil {
        // data came back

A couple of points to notice:

  • in the completion block definition, I specified that both response and error parameters are optionals. You should get one or the other back, but you need to check which one.
  • unlike in Objective-C, you do not have to send in a pointer to the error. The completion handler will send you back an error if it needs to.
  • I used the shorter form of Swift closures but if you let auto-complete do its thing, you will get the longer form which may be more readable.
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download