这就是为什么会有@convention(block)
个,否则编译器会
抱怨无法在中表示此函数
目标-C
出于一致性的考虑:通常反过来使用@convention
属性--当有一个接口接受一个C指针(并用C实现)或一个Objective-C块(用Objective-C实现),而您传递一个带有相应@convention
作为参数的SWIFT闭包时(这样编译器实际上可以为C/Objective-C实现从SWIFT闭包中生成适当的内存布局).因此,如果它是客观C端,那么它应该可以很好地工作,在那里,Swift创建的闭包被称为类似块:
@interface TDWObject : NSObject
- (void)passArguments:(NSDictionary<NSString *, void(^)()> *)params;
@end
如果类向SWIFT公开,则编译器会生成相应的签名,该签名将获取一个包含@convention(block)
个值的字典:
func passArguments(_ params: [String : @convention(block) () -> Void])
然而,这并不能抵消这样一个事实,即属性为@convention
的闭包仍然可以在SWIFT中使用,但当涉及到集合时,事情就变得复杂了,而且它与SWIFT集合的值类型和引用类型的优化有关.为了说明这一点,我建议通过将其提升为[String: AnyObject]
并稍后转换为对应的块类型来明确此集合持有引用类型:
@objc func takeClosures(_ closures: [String: AnyObject]) {
guard let block = closures["One"] else {
return // the block is missing
}
let closure = unsafeBitCast(block, to: ObjCBlock.self)
closure()
}
或者,您可能希望将块包装在一个Objective-C对象中,以便SWIFT清楚地知道它是一个引用类型:
typedef void(^Block)();
@interface TDWBlockWrapper: NSObject
@property(nonatomic, readonly) Block block;
@end
@interface TDWBlockWrapper ()
- (instancetype)initWithBlock:(Block)block;
@end
@implementation TDWBlockWrapper
- (instancetype)initWithBlock:(Block)block {
if (self = [super init]) {
_block = block;
}
return self;
}
@end
然后,对于SWIFT来说,它的工作原理就是这么简单:
@objc func takeBlockWrappers(_ wrappers: [String: TDWBlockWrapper]) {
guard let wrapper = wrappers["One"] else {
return // the block is missing
}
wrapper.block()
}