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.
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")
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")