2

I have a function in my objective c file (lets say class MyBlockExecutor):

+ (void) runBlockFromDictionary: (NSDictionary*) blocksDict andKey: (NSString*) key
{
    if ( [blocksDict objectForKey: key] != nil )
    {
         ((MyBlock)[blocksDict objectForKey: key])();
    }
}

Now, I want to call this function from Swift. Here is my swift call:

MyBlockExecutor.runBlock(from: [
        "key1":{ ()->Void in
                    print("block for key1 called")
               }
        ], andKey: "key1")

This crashes my app. I am getting EXC_BAD_ACCESS error on this line:

((MyBlock)[blocksDict objectForKey: key])();

Although, calling the same function from Objective-C works perfectly fine. Also, I've defined MyBlock as :

typedef void (^MyBlock)(); //defined in MyBlockExecutor.h file

How do I resolve this?

Edit: I am open to changes in the objective c function, I just somehow need to pass a collection of closures from swift to my objective c function and run the block.

0

2 Answers 2

4

You can use a similar approach as in Swift blocks not working: Annotate the block with @convention(block) to use the Objective-C block calling convention, and (explicitly) cast it to AnyObject before putting it into the dictionary:

let myBlock: @convention(block) () -> Void = {
    print("block for key1 called")
}

let dict = ["key1": myBlock as AnyObject]

MyBlockExecutor.runBlock(from: dict, andKey: "key1")

This worked as expected in my test.

It is also similar to what Quinn “The Eskimo!” suggested in the Apple developer forum as a method to pass a closure (defined in Swift) as an Objective-C compatible object through pointers, only that I replaced the unsafeBitCast by the simpler as AnyObject.

You can also write everything inline:

MyBlockExecutor.runBlock(from: ["key1": {
        print("block for key1 called")
    } as @convention(block) () -> Void as AnyObject
    ], andKey: "key1")

or define a helper function:

func objcBlock(from block: @convention(block) () -> Void) -> AnyObject {
    return block as AnyObject
}

MyBlockExecutor.runBlock(from: ["key1": objcBlock {
        print("block for key1 called")
    }], andKey: "key1")
Sign up to request clarification or add additional context in comments.

1 Comment

That worked! Also, can you tell me how to do this inline i.e., I don't want to create myBlock and dict variables.
0

try to break the code in segments and check from where the error is coming.. although its nearly same what you have done we have just break the code in multiple line for debugging easily

//1. create the block instance separately
let myBlockForKey1:MyBlock = { () in
    print("block for key1 called")
}
//2. create dic of blocks as
let dicOfBlocks:[String:MyBlock] = ["key1":myBlockForKey1]
//3. call your function
MyBlockExecutor.runBlock(from: dicOfBlocks, andKey: "key1")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.