这个问题受到了这个问题的启发:Swift closure in array becomes nil in Objective-c,我使用包装类回答了一个解决方法,但我仍然很好奇为什么一个人无法调用,在Objective中-C,通过id
传递的Swift闭包。一个简单的例子如下。
Objective-C代码:
// In a header
typedef void (^EmptyBlock)();
@interface MyClassOC : NSObject
-(void)invoke:(id)blk;
@end
// In an implementation (.m) file
@implementation MyClassOC
-(void)invoke:(id)blk {
EmptyBlock emptyBlock = blk;
emptyBlock();
}
@end
提供Objective-C块没问题:
EmptyBlock block = ^{ puts("In OC empty block..."); };
MyClassOC * myClassOC = [[MyClassOC alloc] init];
[myClassOC invoke:block];
然而,invoke...
中的Objective-C代码无法调用通过id
传入的Swift闭包:
let myClassOC = MyClassOC()
let myBlock : EmptyBlock = {
print("In Swift EmptyBlock...")
}
myClassOC.invoke(myBlock)
我在这一行上以EXC_BAD_ACCESS
结尾:
EmptyBlock emptyBlock = blk;
知道这里发生了什么吗?
答案 0 :(得分:3)
原因可能是Swift 3中引入的支持,任何Swift类型都被表示为Objective-C中id
类型的不透明对象。有关详细信息,请阅读this Apple blog post中的 Objective-C中的Swift值类型。在这种情况下,当参数类型为_SwiftValue *
时,您将看到Swift类型作为id
传递,这是一种不透明的类型。
这种方法的好处是Swift值类型可以存储在Objective-C集合中;但缺点是您无法在Objective-C端转换为Objective-C兼容值。调试代码,您将看到该块作为_SwiftValue *
而不是Objective-C块类型传递。
声明bak
参数以EmptyBlock
类型并且您的代码有效。
HTH
答案 1 :(得分:2)
因为Swift闭包和Objective-C块不是一回事。如果Swift看到您正在调用具有Objective-C块类型的方法,则会自动将闭包转换为Objective-C块,但是否则不会这样做。正如CRD的回答所提到的,在Swift 3中,任何Swift值都可以表示为Objective-C对象,所以即使它看到它需要一个Objective-C对象,它仍然不知道你想要一个Objective-C块,因为一个Swift闭包仍然可以桥接到一个不透明的对象。
我想通过Swift传递它的唯一方法就是:
myClassOC.invoke(myBlock as @convention(block) () -> Void)