如何在Objective-C中实现Swift协议的[String]类型属性?
问题描述
我需要在Objective-C中实现Swift协议定义的[String]类型数组属性。
Swift协议代码
@objc protocol MyProtocol { var myProperty: [String] { get } }
Objective-C实现代码
@interface MyThing : NSObject <MyProtocol> @property (readonly, copy, nonnull) NSArray* myProperty; - (_Nonnull instancetype)init; @end @implementation MyThing - (instancetype)init { self = [super init]; return self; } - (NSArray*)myProperty { return @[@"A value"]; } @end
目前遇到的问题:Objective-C中使用NSArray*,在Swift里会被解析为[Any]类型而非[String],导致Swift中使用MyThing类时,编译器认为协议属性未实现。
请问有没有办法提示编译器该数组为字符串数组?或者让Swift隐式将[Any]数组包装为[String]数组?
我目前想到两种不太理想的解决办法:
- 创建一个封装
[String]数组的Swift类,用该类作为协议属性类型。缺点是若想让该类型无需拆箱即可像数组一样工作,必须实现所有数组方法。 - 定义一个Objective-C可重写的内部属性getter(类型为
[Any]),再添加一个将结果转为字符串数组的便利属性。但这种方式会牺牲类型安全性。
解决方案
直接在Objective-C的属性声明和方法返回值中,使用*带泛型约束的NSArray<NSString *> **来替代NSArray*,就能让Swift自动识别为[String]类型,完美匹配协议要求。
修改后的Objective-C代码如下:
@interface MyThing : NSObject <MyProtocol> @property (readonly, copy, nonnull) NSArray<NSString *>* myProperty; - (_Nonnull instancetype)init; @end @implementation MyThing - (instancetype)init { self = [super init]; return self; } - (NSArray<NSString *>*)myProperty { return @[@"A value"]; } @end
原理说明
Objective-C 2.0开始支持泛型语法,NSArray<NSString *>明确告知编译器该数组的元素均为NSString类型。Swift与Objective-C交互时,会自动将带泛型约束的NSArray<NSString *>桥接为[String],完全符合Swift协议中myProperty: [String]的类型要求,编译器也不会再报错。
这种方法无需额外封装类,也不会牺牲类型安全性,是最直接且优雅的解决方案。
内容的提问来源于stack exchange,提问作者Chris Watts
相关产品推荐
相关产品推荐

