[英]Why do properties modified by @optional become immutable?
我有一个包含如下属性的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
如果我注释掉Playback
协议的@optional
,那么它编译得很好。
这让我想知道为什么@optional
会导致这个错误?
由于它是可选的,Swift 不能保证 setter 的实现。
来自论坛上的Jordan Rose(在实施SE-0070时从事 Swift 工作):
通常可选要求会增加额外的可选性:
- 方法本身成为可选的(
f.bar?()
)- 属性 getter 将值包装在
Optional
的额外级别(if let bar = f.bar
)但是对于属性设置器来说,没有地方可以放置额外的 Optional 级别。 这就是整个故事:我们从来没有想出如何以安全的方式公开可选的属性设置器,并且不想选择任何特定的不安全解决方案。 如果有人能想到一些很棒的东西!
所以答案似乎是:在optional
协议要求被故意限制为 Swift ( SE-0070 ) 中的 Objective-C 协议时,没有决定明确实现的拼写,而且看起来这个功能并不常见,以至于从那以后就没有真正出现过。
直到(如果)这被支持,有两种潜在的解决方法:
向Playback
引入一个显式方法,该方法为assetURL
-setAssetURL:
因为它将被导入 Swift 中,就好像它是属性设置器而不是方法一样,您仍然无法调用它。 (如果您将assetURL
标记为readonly
,这仍然是正确的)extension
中为该方法提供实现,因为您仍然无法分配给协议像在 Swift 中那样做,并引入协议层次结构,例如, AssetBackedPlayback
协议继承自Playback
并提供assetURL
作为非@optional
:
@protocol Playback <NSObject> // Playback methods @end @protocol AssetBackedPlayback: Playback @property (nonatomic, nonnull) NSURL *assetURL; @end
然后,您需要找到一种方法将PlayerController.currentPlayerManager
公开为AssetBackedPlayback
以便分配assetURL
。
约旦的一些其他替代品:
我认为最初推荐的解决方法是“在 Objective-C 中编写一个
static inline
function 来为你做这件事”,但这也不是很好。 如果setValue(_:forKey:)
不在热门路径中,它在实践中也足够好。
The static inline
function recommendation can function similarly to a default protocol implementation, but you do need to remember to call that function instead of accessing the property directly.
setValue(_:forKey:)
也可以工作,但会导致明显的性能损失,因为它通过 Objective-C 运行时支持很多动态,并且比简单的分配要复杂得多。 根据您的用例,成本可能是可以接受的,以避免复杂性!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.