【问题标题】:How to call an objective-c function which accepts Dictionary of blocks as argument from Swift?如何调用一个接受块字典作为Swift参数的objective-c函数?
【发布时间】:2018-02-23 18:35:18
【问题描述】:

我的目标 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 函数并运行该块。

【问题讨论】:

    标签: objective-c swift closures objective-c-blocks


    【解决方案1】:

    您可以使用与Swift blocks not working 类似的方法:使用@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")
    

    这在我的测试中按预期工作。

    这也类似于奎因的“爱斯基摩人!”建议在 the Apple developer forum 作为方法 将闭包(在 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")
    

    【讨论】:

    • 成功了!另外,你能告诉我如何内联吗,即我不想创建 myBlock 和 dict 变量。
    【解决方案2】:

    尝试将代码分段并检查错误的来源。虽然它与您所做的几乎相同,但我们只是将代码分成多行以便轻松调试

    //1. create the block instance separately
    let myBlockForKey1:MyBlock = { () in
        print("block for key1 called")
    }
    //2. create dic of blocks as
    let dicOfBlocks:[String:MyBlock] = ["key1":myBlockForKey1]
    //3. call your function
    MyBlockExecutor.runBlock(from: dicOfBlocks, andKey: "key1")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多