0x0 背景
目前 OC 的泛型使用已经逐渐被 Apple Developer 所接受,可以阅读早期的介绍文章,使用泛型可以更好地保证集合操作的安全性,在类型不符时编译器可以提出警告,而泛型一般在系统框架的集合类型中使用,比如 NSArray,NSDictionary 等。
比如声明带有泛型参数的集合类型变量:
NSArray <NSString *> *names = ...;
NSMutableDictionary <NSNumber *, NSNumber *> *sectionStatus = ...;
又比如,使用 block 的方式遍历带有泛型参数的集合类型时 Xcode 会自动生成内部对象的类型信息:
[array enumerateObjectsUsingBlock:^(SomeClass * _Nonnull obj,
NSUInteger idx,
BOOL * _Nonnull stop) {
// enumerate the array using block
}];
在实际的使用中,有时候会用到将不明确具体类型而是遵循某种特定协议的对象,以 array 为例,可能有如下声明方式
NSArray <SomeProtocol> *array1 = ...;
NSArray <id<SomeProtocol>> *array2 = ...;
NSArray <SomeClass<SomeProtocol> *> *array3 = ...;
那么分析讨论下如何去理解和使用泛型参数为协议的集合。
0x1 分析
- 写法 1:
NSArray <SomeProtocol> *array1
认真地看,其实这不是泛型数组,而是遵循了 SomeProtocol 的数组对象。 - 写法 2:
NSArray <id<SomeProtocol>> *
这种写法完全正确,编译器会有很好的泛型支持,可以联想类比 UITableView 的 delegate 声明,所表达的含义是任意遵循SomeProtocol
的 OC 对象
// objc.h
typedef struct objc_object *id
- 写法 3:
NSArray <SomeClass<SomeProtocol> *> *
也符合要求,与写法 2 的区别在于,这次泛型参数要求对象遵循协议的同时还要继承自某个类(在这里是继承自SomeClass
)。
根据上述分析,不难得出如上三种写法桥接到 Swift 的结果:
let array1: [Any] = ...;
let array2: [SomeProtocol] = ...;
let array3: [SomeClass & SomeProtocol] = ...;
也就是说写法 1 的对应到 Swift 为 Any
Array 类型,这是 OC 数组因为桥接后没有了协议信息,如果是普通对象则不会,例如:
- (void)funcWithObject:(SomeClass<SomeProtocol> *)object;
桥接到 Swift 则是这样:
func func(withObject object: SomeClass & SomeProtocol)
而后面两种则符合预期的表现,实际开发中应避免看似简便实际无效的写法 1,根据场景使用写法 2 或者写法 3。
~~~ 加个V,交个友 😆
V🌊:@席萍萍Brook
V❤️:↓↓
EOF
网友评论