Swift协议定义的Objective-C属性能否用@synthesize实现?
能否在Objective-C中合成Swift @objc协议定义的属性?
问题场景
我在Swift里定义了一个带@objc标记的协议:
@objc protocol Themeable: class { @objc var themeGradient: Gradient { get set } }
之后在Objective-C的视图控制器里尝试遵循这个协议,并用@synthesize来实现协议要求的属性:
#import "MyProject-Swift.h" @interface MyObjcViewController () <Themeable> @end; @implementation MyObjcViewController @synthesize themeGradient; ... @end
但编译时卡在@synthesize这一行,报错:
Error: Property implementation must have its declaration in interface 'MyObjcViewController' or one of its extensions
答案:不能直接合成,需要先在Objective-C类的接口/扩展中显式声明属性
Objective-C的@synthesize规则很明确:它只能处理当前类的接口(或其扩展)里显式写出来的属性声明。虽然Swift的@objc协议会把属性要求暴露给Objective-C,但这些要求并不会自动在你的OC类接口里生成对应的属性声明——编译器找不到要合成的属性定义,自然就报错了。
两种解决办法
1. 在类扩展中声明属性再合成
最简单的方式就是在遵循协议的扩展里,把协议要求的属性显式声明出来,之后就能正常用@synthesize了:
#import "MyProject-Swift.h" @interface MyObjcViewController () <Themeable> // 显式添加属性声明 @property (nonatomic, strong) Gradient *themeGradient; @end; @implementation MyObjcViewController @synthesize themeGradient; // 现在可以直接使用themeGradient属性 ... @end
2. 手动实现存取方法(无需@synthesize)
如果你不想用@synthesize,也可以直接手动实现协议要求的getter和setter方法——毕竟协议本质上只是要求类提供这两个方法。可以自己加个私有实例变量来存储值:
#import "MyProject-Swift.h" @interface MyObjcViewController () <Themeable> // 私有实例变量,用来存储属性值 @property (nonatomic, strong) Gradient *_themeGradient; @end; @implementation MyObjcViewController - (Gradient *)themeGradient { return _themeGradient; } - (void)setThemeGradient:(Gradient *)themeGradient { _themeGradient = themeGradient; } ... @end
额外说明
当OC类遵循Swift的@objc协议时,协议的get set属性要求其实等价于要求类实现-themeGradient和-setThemeGradient:这两个方法。所以不管你用哪种方式,只要满足这两个方法的实现,就能通过协议的一致性检查。
内容的提问来源于stack exchange,提问作者Eneko Alonso
相关产品推荐
相关产品推荐

