夫特封闭件成为零目标C
我创建一个Objective-C方法,该方法将通过NSInvocation的调用方法:夫特封闭件成为零目标C
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:
在子类中,然后执行调用。
所有这些工作,除了当被调用的方法有块参数他们是零,我添加了测试为零我说与评论,当试图从数组中读闭,它将是零。
调用,如:
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)
为什么封成为零?
我必须承认,我不完全明白为什么会发生这种情况,但据我所知,这与使用NSInvocation
无关,即使我们只是将Swift闭包传递给Objective-C功能通过id
类型的参数。通过id
传递Objective-C块的工作很好,不知道为什么:Swift闭包应该与Objective-C块兼容。如您所知,NSArray
的元素类型为id
,因此任何Objective-C对象都可以是数组元素。
要解决访问在Objective-C中通过id
传递的Swift闭包的问题,可以引入一个包装类。
// In a header:
@interface EmptyBlockWrapper : NSObject
@property EmptyBlock _blk;
@end
// In an implementation file (just an empty implementation):
@implementation EmptyBlockWrapper
@end
然后,我们可以使用一个包装实例的代替块作为在夫特数组元素:
let myBlock : EmptyBlock = {
print("In Swift EmptyBlock...")
}
let myBlockWrapper = EmptyBlockWrapper()
myBlockWrapper._blk = myBlock
在一个Objective-C方法我们可以称之为如下,假设args
是NSArray *
:
EmptyBlockWrapper * emptyBlockWrapper = args[1];
emptyBlockWrapper._blk();
希望这会有所帮助。当然,这只是给你一个想法的简单例子;这可能会变得更加奇特。
success
是不nil
(事实上,NSArray
不能包含nil
多个)。如果你打印它像NSLog(@"%@", success);
,它会说(Function)
,而不是(null)
。如果您打印类似NSLog(@"%@", [success class]);
,它会说_SwiftValue
。基本上,它是一个桥接到Objective-C中的Swift值。
问题是指向的对象success
不是Objective-C块。它是一个Swift闭包,Swift闭包与Objective-C块不同。试图用它来调用它,就好像它是一个Objective-C块一样会导致未定义的行为。 po
在调试器中打印错误可能是因为它打印它假定它是ScriptingEmptyBlock
(块类型)。如果你这样做po (id) success
,它会打印(Function)
。
至于你怎么能明确提出一个Objective-C块到从斯威夫特的阵列,只有这样,我想通了,这样做是这样的:
let params:[Any] = [ "testName",
successClosure as (@convention(block)() -> Void)!,
errorClosure as (@convention(block) (NSError) -> Void)!]
object.scripting_execute (ScriptOperation.updateProductName.rawValue,
withParams: params)
我不知道为什么有必要把!
中的函数类型,但它似乎不起作用。也许别人可以找到更好的方法。