我有一個 Swift 物件,它接受一個塊字典(由字串鍵控),存盤它并稍后根據外部情況在給定鍵下運行塊(根據后端回應考慮不同的行為):
@objc func register(behaviors: [String: @convention(block) () -> Void] {
// ...
}
它用于混合語言專案,因此需要從 Swift 和 Objective-C 均可訪問。這就是為什么有@convention(block),否則編譯器會抱怨無法在 Objective-C 中表示這個函式。
它在 Swift 中運行良好。但是當我嘗試像這樣從 Objective-C 呼叫它時:
[behaviorManager register:@{
@"default": ^{
// ...
}
}];
代碼崩潰,我收到以下錯誤:
Could not cast value of type '__NSGlobalBlock__' (0x...) to '@convention(block) () -> ()' (0x...).
這是為什么,這是怎么回事?我想@convention(block)是專門告訴編譯器將要傳遞目標 C 塊,而這正是在呼叫中傳遞給函式的內容。
uj5u.com熱心網友回復:
這就是為什么有
@convention(block),否則編譯器會抱怨無法在 Objective-C 中表示這個函式
為了一致性起見:通常您使用@convention相反的屬性 - 當有一個介面采用 C 指標(并在 C 中實作)或 Objective-C 塊(并在 Objective-C 中實作)時,您通過一個對應的 Swift 閉包,@convention而不是作為引數(因此編譯器實際上可以從 Swift 閉包中為 C/Objective-C 實作生成適當的記憶體布局)。因此,如果它是 Swift 創建的閉包被稱為塊的 Objective-C 端,它應該可以正常作業:
@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()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/529046.html
