Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Swift 2 closure to Objective-C block

I'm trying to build an Objective-C block in Swift 2 in order to add it to an NSArray like so :

typealias CompletionBlock = () -> Void
let aBlock:CompletionBlock =  {
    print("Hello world!")
}
let nsArray = NSMutableArray()
nsArray.addObject(aBlock) // Error

I know it will work just fine with a Swift array, but I need an NSArray here for compatibility with existing Objective-C code. And if I use a swift array the compiler will refuse to cast it to an NSArray because it won't be a [AnyObject] (it will be a [Any]).

The problem here is that a swift closure is not an object contrary to Objective-C blocks which are objects behind the scene (they are instances of NSBlock which is a subclass of NSObject)

So my question is : How do a create an Objective-C block in swift ? I've tried using @convention (block) in the typealias but it doesn't work.

like image 783
deadbeef Avatar asked Feb 12 '16 12:02

deadbeef


1 Answers

EDIT : As of Swift 3, this is completely unnecessary (and doesn't even work). Adding closures to Objective-C arrays works out of the box in Swift 3. The answer below is valid for Swift 2 only.

I know this is a duplicate but I will still post a refactored answer from swift-closure-as-anyobject and cast-closures-blocks in case anyone lands on this one first.

The solution is to use the unsafeBitCast function to convert the Swift closure to an Objective-C compatible object before adding it to an NSArray and back before using it in Swift.

// The `@convention(block)` is important here in order to get
// Objective-C like memory management
typealias CompletionBlock = @convention(block) () -> Void

let aBlock:CompletionBlock = {
    print("Hello world!")
}
let nsArray = NSMutableArray()
let blockObject = unsafeBitCast(aBlock, AnyObject.self)
nsArray.addObject(blockObject)

let closureObject = nsArray[0]
let closure = unsafeBitCast(closureObject, CompletionBlock.self)
closure()
like image 96
deadbeef Avatar answered Nov 09 '22 20:11

deadbeef