ios - Objective-c 中数组中的 Swift 闭包变为 nil

标签 ios objective-c memory-management swift3 objective-c-blocks

我创建了一个 Objective-C 方法,它将通过 NSInitation 调用一个方法:

typedef void (^ScriptingEmptyBlock)();
typedef void (^ScriptingErrorBlock)(NSError *error);
- (void)scripting_execute:(NSString *)operation withParams:(nullable NSArray *)args {

    SEL selector = [self scripting_selectorForOperation:operation];
    Class class = [self class];
    NSMethodSignature *signature = [class instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

    [invocation setSelector:selector];
    [invocation setTarget:self];
    for (int idx = 0; idx < args.count; idx ++) {
        id arg = args[idx];
        [invocation setArgument:&arg atIndex:idx + 2];

    }

    ScriptingEmptyBlock success = args[1];

    // Breakpoint added on next line to test for nil
    success(); // this is nil and would crash!
    // (lldb) po args.count
    // 3

    // (lldb) po success
    // Printing description of success:
    // (ScriptingEmptyBlock) success = 0x0000000000000000

    // (lldb) po args[1]
    // (Function)

    //[invocation getArgument:&success atIndex:2]; // also tried this and got nil as well
    [invocation invoke];

}

该方法采用一个“操作”,通过重写子类中的 scripting_selectorForOperation: 将其转换为选择器,然后执行调用。

所有这些都有效,除了当调用的方法具有 block 参数时它们为零时,我添加了我用注释描述的 nil 测试,当尝试从数组读取闭包时它将为零。

调用方式如下:

let successClosure: ScriptingEmptyBlock = {
                    print("Renamed product")
                }
let errorClosure: ScriptingErrorBlock = { error in
                    print("Failed to rename product: \(error)")
                }
let params:[Any] = [ "testName", successClosure, errorClosure]
object.scripting_execute (ScriptOperation.updateProductName.rawValue, withParams: params)

为什么闭包变为零?

最佳答案

success 不是 nil(事实上,NSArray 不能包含 nil s)。如果你像 NSLog(@"%@", success); 那样打印它,它会显示 (Function),而不是 (null)。如果您像 NSLog(@"%@", [success class]); 那样打印它的类,它会显示 _SwiftValue。基本上,它是一个桥接到 Objective-C 中的 Swift 值。

问题是 success 指向的对象不是 Objective-C block 。它是一个 Swift 闭包,Swift 闭包与 Objective-C block 不同。尝试像使用 Objective-C block 一样调用它会导致未定义的行为。调试器中的 po 打印错误可能是因为它假设它是类型 ScriptingEmptyBlock ( block 类型)。如果你执行po (id) success,它将打印(Function)

至于如何从 Swift 显式地将 Objective-C block 放入数组中,我想到的唯一方法是:

let params:[Any] = [ "testName",
                     successClosure as (@convention(block) () -> Void)!,
                     errorClosure as (@convention(block) (NSError) -> Void)!]
object.scripting_execute (ScriptOperation.updateProductName.rawValue,
                          withParams: params)

我不确定为什么需要将函数类型放入 ! 中,但它似乎不起作用。也许其他人可以找到更好的方法。

关于ios - Objective-c 中数组中的 Swift 闭包变为 nil,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45685366/

相关文章:

ios - Swift 如何从两个文本字段中获取 Int 并生成随机数

ios - 使用 Firebase 与企业数据库进行离线数据同步

python - Python递归期间的内存使用

ios - 不会调用其他类中的方法,Objective-C

iphone - 即使在 scrollEnabled 设置为 NO 后,UIWebview 仍会重新启用滚动

c++ - 我可以只使用固定数组而不是内存池吗?

c - 使用 malloc 时触发异常

ios - 如何使用 Storyboard iOS 来布局单个 View 的纵向和横向方向?

ios - 在同一列表/表格 View 中显示缓存的服务器联系人和本地 iOS 联系人

objective-c - ios中的二维数组