数组中的 Swift 闭包在 Objective-c 中变为 nil [英] Swift closure in array becomes nil in Objective-c

查看:19
本文介绍了数组中的 Swift 闭包在 Objective-c 中变为 nil的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个objective-c方法,它将通过NSInvocation调用一个方法:

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

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: 将操作"转换为选择器,然后执行调用.

The method takes an "operation" which is translated into a selector by overriding scripting_selectorForOperation: in subclasses and then performs the invocation.

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

All of that works, except when the invoked method has block arguments they are nil, I added the test for nil I describe with comments, when attempting to read the closure from the array it will be 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)

为什么闭包变成了 nil?

Why is closure becoming nil?

推荐答案

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

success is not nil (in fact, NSArray cannot contain nils). If you print it like NSLog(@"%@", success);, it will say (Function), not (null). And if you print its class like NSLog(@"%@", [success class]);, it will say _SwiftValue. Basically, it is a Swift value that is bridged into Objective-C.

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

The problem is that the object success points to is not an Objective-C block. It is a Swift closure, and Swift closures are not the same as Objective-C blocks. Trying to use invoke it as if it were an Objective-C block causes undefined behavior. po in the debugger prints it wrong probably because it is printing it assuming it were type ScriptingEmptyBlock (a block type). If you do po (id) success, it will print (Function).

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

As to how you can explicitly put an Objective-C block into the array from Swift, the only way I figured out to do it something like:

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

我不知道为什么有必要将函数类型放在 ! 中,但它似乎不工作.也许其他人可以找到更好的方法.

I am not sure why it's necessary to put the function type inside a !, but it doesn't seem to work otherwise. Maybe someone else can find a better way.

这篇关于数组中的 Swift 闭包在 Objective-c 中变为 nil的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆