How do I cast an __NSMallocBlock__ to its underlying type in Swift 3?

后端 未结 3 1540
隐瞒了意图╮
隐瞒了意图╮ 2021-01-05 11:25

I had a trick to help test UIAlertController that worked in Swift 2.x:

extension UIAlertController {

    typealias AlertHandler = @convention(b         


        
3条回答
  •  醉话见心
    2021-01-05 11:30

    My answer is based on @Robert Atkins's, but shorter. The problem here is that, valueForKey returns a Any typed object, and because in Swift,

    MemoryLayout.size == 32
    MemoryLayout.size == 8
    

    an assertion will be triggered in unsafeBitCast when casting between types of different sizes.

    One work-around is to create an intermediate wrapper and transform back to raw pointer, which satisfies MemoryLayout.size == 8.

    A much simpler way is to create an indirect reference directly using protocol AnyObject, relying on the fact that MemoryLayout.size == 8, we can write following valid code:

    typealias AlertHandler = @convention(block) (UIAlertAction) -> Void
    
    func tapButton(atIndex index: Int) {
        if let block = actions[index].value(forKey: "handler") {
            let handler = unsafeBitCast(block as AnyObject, to: AlertHandler.self)
            handler(actions[index])
        }
    }
    

提交回复
热议问题