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

查看:295
本文介绍了在Objective-c中,数组中的Swift闭包变为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.

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

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 (事实上, NSArray 不能包含 nil s)。如果你打印它像 NSLog(@%@,成功); ,它会说(功能),不是(null)。如果你打印它的类如 NSLog(@%@,[成功类]); ,它会说 _SwiftValue 。基本上,它是一个Swift值,它被桥接到Objective-C。

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.

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

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.

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

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