iOSエッセイ——初識列挙器enumerateObjectsUsingBlock

2268 ワード

列挙器はアップルが公式に推薦したよりオブジェクト向けの遍歴方式であり、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;
    }
}

このような処理方法もアップルの公式がもっとお勧めする方法だと信じています.