iOS随笔——初识枚举器enumerateObjectsUsingBlock

枚举器是一种苹果官方推荐的更加面向对象的一种遍历方式,相比于for循环,它具有高度解耦、面向对象、使用方便等优势

1.测试场景

一个未知内部数据的数组,判断数组中是否有字符串@"2"
方式:通过遍历,判断数组元素是否等于@"2"

[@[@"1",@"2",@"3"] enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isEqualToString:@"2"]) {
            NSLog(@"smart string is at index %lu",(unsigned long)idx);
            *stop = YES;
        }
    }];

打印信息:smart string is at index 1

2.实现原理

你是否思考过它的内部实现方式?
那么让我们来重写一个它的内部实现,通过NSArray的分类给外界提供一个测试方法,来模拟它的内部实现(不开源,只能猜测 0^0)

- (void)enumTestBlock:(void (^)(id, NSUInteger, BOOL *))enumBlock {
    if (!enumBlock && self.count == 0) return;
    BOOL stop = NO;
    for (int index = 0; index < self.count; index++ ) {
        if (!stop) {
            enumBlock(self[index], index, &stop);
        } else {
            break;
        }
    }
}

外部调用:

 [@[@"1",@"2",@"3"] enumTestBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj isEqualToString:@"2"]) {
            NSLog(@"smart test string is at index %lu",(unsigned long)idx);
            *stop = YES;
        }
    }];

打印信息:smart test string is at index 1


这里唯一需要注意就是Block内传入的一个bool类型的指针参数BOOL *stop,是为了外部能在同一内存地址上修改内部实现中的变量stop的值,来实现跳出循环的功能


3.自定义枚举器实战场景

在看MJExtension源码时发现了这种有意思的自定义枚举器,用于遍历所有的类,直到遇到Foundation类时跳出循环

typedef void (^MJClassesEnumeration)(Class c, BOOL *stop);
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration {
    // 1.没有block就直接返回
    if (enumeration == nil) return;
    // 2.停止遍历的标记
    BOOL stop = NO;
    // 3.当前正在遍历的类
    Class c = self;
    // 4.开始遍历每一个类
    while (c && !stop) {
        // 4.1.执行操作
        enumeration(c, &stop);
        // 4.2.获得父类
        c = class_getSuperclass(c);
        if ([MJFoundation isClassFromFoundation:c]) break;
    }
}

相信这样的处理方式也是苹果官方更推荐的一种方式

你可能感兴趣的:(iOS随笔——初识枚举器enumerateObjectsUsingBlock)