我有一個包含如下屬性的Objective-C協議:
#import <Foundation/Foundation.h>
@protocol Playback <NSObject>
@optional
@property (nonatomic, nonnull) NSURL *assetURL;
@end
PlayerController有一個型別的屬性id<Playback>:
@interface PlayerController: NSObject
@property (nonatomic, strong, nonnull) id<Playback> currentPlayerManager;
@end
我嘗試在Swift 中撰寫以下代碼,但出現錯誤:
var player = PlayerController()
var pla = player.currentPlayerManager
pla.assetURL = URL(string: "123") // ? Cannot assign to property: 'pla' is immutable
如果我注釋掉@optional的Playback 協議,那么它編譯罰款。
這讓我想知道為什么@optional會導致這個錯誤?
uj5u.com熱心網友回復:
從喬丹·羅斯(誰在那個時間上斯威夫特作業SE-0070開始實施)在論壇上:
通常可選要求會增加額外的可選性:
- 方法本身成為可選的 (
f.bar?())- 屬性 getter 將值包裝在
Optional(if let bar = f.bar)的額外級別中但是沒有地方可以為屬性設定器放置額外的 Optional 級別。這就是整個故事:我們從未想出如何以安全的方式公開可選的屬性設定器,也不想選擇任何特定的不安全解決方案。如果有人能想到什么就太好了!
所以答案似乎是:當時optional協議要求被有意限制為 Swift ( SE-0070 ) 中的Objective-C 協議,沒有決定明確實作的拼寫,而且這個功能似乎很不常見從那以后就沒有真正出現過。
在(并且如果)支持此之前,有兩種潛在的解決方法:
引入一個顯式方法
Playback,為其賦值assetURL- 遺憾的是,這個方法無法命名,
-setAssetURL:因為它會被匯入到 Swift 中,就好像它是屬性設定器而不是方法一樣,而且您仍然無法呼叫它。(如果你標記assetURL為,這仍然是真的readonly) - 同樣遺憾的是,此方法將無法有默認實作,因為 Objective-C 不支持默認協議實作,并且您無法在 Swift 中為該方法提供實作,
extension因為您仍然無法分配給協議
- 遺憾的是,這個方法無法命名,
像在 Swift 中一樣,引入協議層次結構,例如,
AssetBackedPlayback協議繼承自Playback并assetURL作為非@optional屬性提供:@protocol Playback <NSObject> // Playback methods @end @protocol AssetBackedPlayback: Playback @property (nonatomic, nonnull) NSURL *assetURL; @end然后,您需要找到一種公開
PlayerController.currentPlayerManager為 an 的方法AssetBackedPlayback,以便將assetURL.
約旦的一些其他替代品:
我認為最初推薦的解決方法是“
static inline在 Objective-C 中撰寫一個函式來為你做這件事”,但這也不是很好。setValue(_:forKey:)如果它不在熱門路徑中,在實踐中也可以足夠好。
該static inline功能推薦功能類似于一個默認的協議實作,但你必須記住呼叫該函式,而不是直接訪問屬性。
setValue(_:forKey:)也可以作業,但會導致明顯的性能損失,因為它通過 Objective-C 運行時支持很多動態,并且比簡單的賦值復雜得多。根據您的用例,為了避免復雜性,成本可能是可以接受的!
uj5u.com熱心網友回復:
由于它是可選的,Swift 不能保證 setter 被實作。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/378447.html
標籤:迅速 目标-c Objective-c-swift-bridge 目标-c-协议
