一尘不染

如何调用一个Objective-C函数,它接受Swift的块字典作为参数?

swift

我的目标c文件中有一个函数(比如说MyBlockExecutor类):

+ (void) runBlockFromDictionary: (NSDictionary*) blocksDict andKey: (NSString*) key
{
    if ( [blocksDict objectForKey: key] != nil )
    {
         ((MyBlock)[blocksDict objectForKey: key])();
    }
}

现在,我想从Swift调用此函数。这是我的快速电话:

MyBlockExecutor.runBlock(from: [
        "key1":{ ()->Void in
                    print("block for key1 called")
               }
        ], andKey: "key1")

这会使我的应用程序崩溃。我在这条线上收到EXC_BAD_ACCESS错误:

((MyBlock)[blocksDict objectForKey: key])();

虽然,从Objective-C调用相同的功能非常好。另外,我将MyBlock定义为:

typedef void (^MyBlock)(); //defined in MyBlockExecutor.h file

我该如何解决?

编辑:我对目标c函数的更改持开放态度,我只是需要以某种方式将闭包的集合从swift传递到我的目标c函数并运行该块。


阅读 302

收藏
2020-07-07

共1个答案

一尘不染

您可以使用与Swift块不起作用类似的方法:@convention(block) 使用Objective-
C块调用约定对块进行注释,并(明确地)将其AnyObject强制转换为字典之前:

let myBlock: @convention(block) () -> Void = {
    print("block for key1 called")
}

let dict = ["key1": myBlock as AnyObject]

MyBlockExecutor.runBlock(from: dict, andKey: "key1")

这按我的测试预期工作。

它也类似于奎因的《爱斯基摩人》。在Apple开发人员论坛中建议
将其作为通过指针传递闭包(在Swift中定义)作为与Objective-C兼容的对象的方法,只有我用unsafeBitCast 更简单的代替了as AnyObject

您还可以内联编写所有内容:

MyBlockExecutor.runBlock(from: ["key1": {
        print("block for key1 called")
    } as @convention(block) () -> Void as AnyObject
    ], andKey: "key1")

或定义一个辅助函数:

func objcBlock(from block: @convention(block) () -> Void) -> AnyObject {
    return block as AnyObject
}

MyBlockExecutor.runBlock(from: ["key1": objcBlock {
        print("block for key1 called")
    }], andKey: "key1")
2020-07-07