Для чого використовується аргумент BOOL * stop для enumerateObjectsUsingBlock: для якого використовується?


87

enumerateObjectsUsingBlock:Останнім часом я багато використовую для своїх потреб швидкого перерахування, і мені важко зрозуміти використання BOOL *stopв блоці перерахування.

Стан NSArrayпосилання на клас

stop: Посилання на логічне значення. Блок може встановити значення, YESщоб зупинити подальшу обробку масиву. stopАргумент є через єдиний аргумент. Ви повинні будь-коли встановлювати для цього логічного значення YESлише Блок.

Тоді, звичайно, я можу додати в свій блок наступне, щоб зупинити перелік:

if (idx == [myArray indexOfObject:[myArray lastObject]]) {
    *stop = YES;
}

З того, що я був в змозі сказати, явно не установка *stopна YESне має яких - небудь негативних побічних ефектів. Здається, перелік автоматично зупиняється в кінці масиву. Тож чи *stopдійсно необхідне використання в блоці?

Відповіді:


156

stopАргумент блоку дозволяє зупинити перерахування передчасно . Це еквівалент breakзвичайного forциклу. Ви можете ігнорувати це, якщо хочете пройти кожен об’єкт у масиві.

for( id obj in arr ){
    if( [obj isContagious] ){
        break;    // Stop enumerating
    }

    if( ![obj isKindOfClass:[Perefrigia class]] ){
        continue;    // Skip this object
    }

    [obj immanetizeTheEschaton];
}

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if( [obj isContagious] ){
        *stop = YES;    // Stop enumerating
        return;
    }

    if( ![obj isKindOfClass:[Perefrigia class]] ){
        return;    // Skip this object
    }

    [obj immanentizeTheEschaton];
}];

Це параметр out, оскільки це посилання на змінну із області виклику. Його потрібно встановити всередині вашого блоку, але читати всередині enumerateObjectsUsingBlock:, так само NSError, як зазвичай передаються назад до вашого коду із фреймворкових викликів.

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
    // N.B: This is probably not how this method is actually implemented!
    // It is just to demonstrate how the out parameter operates!

    NSUInteger idx = 0;
    for( id obj in self ){

        BOOL stop = NO;

        block(obj, idx++, &stop);

        if( stop ){
            break;
        }
    }
}

21
Зверніть увагу, що stopпрапор є дорадчим; наприклад, перелік може продовжуватись для деякої невизначеної кількості ітерацій у паралельному випадку. Тобто не слід __blockбезумовно встановлювати змінну при кожному проходженні через перерахування і очікувати, що це буде "останнє" значення при використанні stopдля дострокового завершення. Завжди слід поєднувати параметр "ні, використовуй цей об'єкт" із налаштуванням stop = YES;.
bbum

@bbum, ти можеш пояснити, чи продовжується поведінка лише для одночасного перерахування? Хоча це цілком зрозуміло в такому випадку, це не задокументовано, і це буде досить дивовижним укусом для "серійного" перелічення.
jscs

4
<rdar: // problem / 15015199> тепер просить пояснити, оскільки в документації не сказано ні того, ні іншого.
bbum
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.