Swift closure in array becomes nil in Objective-c

前端 未结 2 478
死守一世寂寞
死守一世寂寞 2020-12-21 10:14

I created an objective-c method which will invoke a method via NSInvocation:

typedef void (^ScriptingEmptyBlock)();
typedef void (^ScriptingErrorBlock)(NSErr         


        
2条回答
  •  伪装坚强ぢ
    2020-12-21 10:54

    I must admit that I don't fully understand why this is happening, but as far as I can tell this has nothing to do with using NSInvocation and would happen even if we just passed a Swift closure to an Objective-C function via a parameter of type id. Passing an Objective-C block via id works just fine, not sure why: Swift closures are supposed to be compatible with Objective-C blocks. As you know, elements of NSArray are of type id, so any Objective-C object can be an array element.

    To work around this problem of accessing a Swift closure passed via id in Objective-C one can introduce a wrapper class.

    // In a header:
    @interface EmptyBlockWrapper : NSObject
    @property EmptyBlock _blk;
    @end
    
    // In an implementation file (just an empty implementation):
    @implementation EmptyBlockWrapper
    
    @end
    

    Then we can use a wrapper instance instead of a block as an array element in Swift:

    let myBlock : EmptyBlock = {
        print("In Swift EmptyBlock...")
    }
    
    let myBlockWrapper = EmptyBlockWrapper()
    myBlockWrapper._blk = myBlock
    

    In an Objective-C method we can call it as follows, assuming args is NSArray *:

    EmptyBlockWrapper * emptyBlockWrapper = args[1];
    emptyBlockWrapper._blk();
    

    Hopefully this is helpful. Of course, this is just a simplified example to give you an idea; this could be made much fancier.

提交回复
热议问题