好久没写些什么东西了,似乎快有半年了吧。也不知道要写些什么,最近也跳槽了,复习了一段时间,所以应该重新开启新的行程了。
废话不多说,今天来研究下NSFastEnumeration
这个协议。
for循环
遍历集合一般都想到使用for
循环,这是一个很基本的办法,因此功能十分有限,通常会这样写代码:
1 | NSArray *array = /* ... */; |
假设我们要遍历字典,就会先获取到字典所有的key
,然后再通过key
获取value
,因为字典是无序的,所以无法根据特点的整数下标来直接访问其中的值. 这样就需要转化,就很麻烦。
NSEnumerator
在Objective-C 1.0
的时候,我们可以使用NSEnumerator
来遍历, NSEnumerator
是个抽象类,只定义了1个方法和一个属性:
1 | - (nullable ObjectType)nextObject; |
如果我们想遍历数组,可以这样:
1 | NSArray *array = /* ... */; |
这种写法与for
循环差不多,但是代码量似乎变多了
NSFastEnumeration
在Objective-C 2.0
引入了一种快速遍历的方法,我们可以直接使用for in
关键字
1 | NSArray *array = /* ... */; |
这样写是不是就简单了很多。但是这个for in
只是一个语法糖, 但是具体底层是怎么实现的呢? 我们先来看一下NSArray
类的头文件NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
会发现它实现了NSFastEnumeration
这么个协议。也正是这个协议,支持了for in
这种语法。
这个协议只有一个方法和一个结构体。
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained _Nullable [_Nonnull])buffer count:(NSUInteger)len;
1 | typedef struct { |
看到这个结构体。。。简直一脸懵逼。。。这是个什么玩意? 于是只能去查下官方文档了,在官方demo中我们看到了这个协议方法的实现,跟这个结构体的含义。
1 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state |
将注释翻译一下,剩下的代码是这样,countByEnumeratingWithState:
一共有两种实现方式,通过宏来控制. 我们可以看出:
1 | * countByEnumeratingWithState是被外部循环调用的 |
通过上面的了解后,接下来,我们通过一个小例子来说明for in
是如果工作的.
简单的写了一个数组遍历的代码:
1 | int main(int argc, const char * argv[]) { |
然后我们通过clang -rewrite-objc main.m
, 然编译器翻译下for in
,我们会看到一个.cpp
的文件,里面代码实在是太多了, 我们找到我们写的那个地方,
1 | id obj; |
其实for in
快速遍历是通过两层 do/while
循环来实现的, 外层循环负责调用 - countByEnumeratingWithState:objects:count:
方法,获取 C
数组,内层循环则负责遍历获取到的 C
数组, 通过mutationsPtr
值的变化来判断集合在遍历过程中是否突变.
通过对NSFastEnumeration
的学习,了解了for in
快速遍历是如何实现的.
最后更新: 2023年03月25日 22:39:55
本文链接: http://aeronxie.github.io/post/a454a4e0.html
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可,转载请注明出处!