Here is the Objective-C block:
@property (copy) void (^anObjcBlock)();
anObjcBlock = ^{
NSLog(@"Yea man this thing works!!");
};
NSMutableArray *theArrayThatHasTheBlockInItAtIndexZero = [NSMutableArray array];
[theArrayThatHasTheBlockInItAtIndexZero addObject:anObjBlock];
Here's what I did in Swift:
var theBlock: (()->Void)?
theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as? ()->Void
// Now call the block
theBlock!()
But with this I get runtime error.
Basically, the theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as? ()->Void
statement would make theBlock
nil because the as?
failed. And when I changed the statement to theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as! ()->Void
, I get a runtime error:
I'm not sure what else to do. This is an empty project, there really is no code in it.
It looks like the issue, in this case, comes from the NSMutableArray.
[NSMutableArray objectAtIndex:] returns id in Objective-C, which gets translated to AnyObject by Swift.
You will get an error if you attempt to cast AnyObject to () ->Void.
A workaround is the following:
// Create your own typealias (we need this for unsafeBitcast)
typealias MyType = @convention(block) () -> Void
// Get the Obj-C block as AnyObject
let objcBlock : AnyObject = array.firstObject! // or [0]
// Bitcast the AnyObject Objective-C block to a "Swifty" Objective-C block (@convention(block))
// and then assign the result to a variable of () -> Void type
let block : () -> Void = unsafeBitCast(objcBlock, MyType.self)
// Call the block
block()
This code works for me.
FUNNY FACT
If you edit your Objective-C code to look like this...
// Typedef your block type
typedef void (^MyType)();
// Declare your property as NSArray of type MyType
@property (strong) NSArray<MyType>* array;
Swift will now report the array type as [MyType]!.
For some reason, generics on NSMutableArray doesn't seem to be picked up by Swift.
Despite that, you'll get a runtime error if you execute:
let block : MyType? = array[0]