Как цикл for in работает внутри - Objective C - Foundation

Я нашел такой ответ:

https://stackoverflow.com/a/5163334/1364174

Это показывает, как реализован цикл for in.

NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
    for (NSUInteger i = 0; i < __count; i++) {
        id obj = __objects[i];
        [obj doSomething];
    }
}

Проблема в том, что я ошибся.

Прежде всего, когда у вас включен автоматический подсчет ссылок (ARC), вы получаете ошибку

Sending '__strong id *' to parameter of type '__unsafe_unretained_id*' changes retain/release properties of pointer

Снимок экрана с ошибкой

Но даже когда я выключил ARC, я обнаружил, что массив I __object ведет себя странно:

Скриншот ошибки2

Это фактический код (я предположил, что MAX_STACKBUFF_SIZE равно 40):

@autoreleasepool {

        NSArray *myArray = @[@"a", @"b", @"c", @"d", @"e", @"f", @"g"];
        int MAX_STACKBUFF_SIZE = 40;
        NSFastEnumerationState __enumState = {0};
        id __objects[MAX_STACKBUFF_SIZE];
        NSUInteger __count;
        while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
            for (NSUInteger i = 0; i < __count; i++) {
                id obj = __objects[i];
                __enumState.itemsPtr
                NSLog(@" Object from __objects ! %@", obj);  // on screenshot different message

            }
        }

    }
    return 0;

Я получил EXC_BAD_ACESS, когда пытаюсь получить содержимое массива __object. Я также обнаружил, что когда вы пытаетесь перебрать __enumState.itemsPtr, он действительно работает.

Не могли бы вы объяснить мне, что здесь происходит? Почему мой __objects кажется "съежившимся". И почему в нем нет желаемого объекта? И почему та ошибка при включении ARC.

Заранее большое спасибо за ваше время и усилия! (Я предоставил снимок экрана, чтобы лучше понять, что вызывает ошибку)


person Paul Brewczynski    schedule 21.12.2013    source источник
comment
Я не понимаю, почему бы просто не использовать for in ___?   -  person Mick MacCallum    schedule 22.12.2013
comment
@ 0x7fffffff Я пытаюсь понять реализацию цикла for in.   -  person Paul Brewczynski    schedule 22.12.2013
comment
@bluesm Не воспринимайте код в этом ответе буквально. В лучшем случае это псевдокод . Это почти наверняка не то, как создатели компилятора реализовали цикл.   -  person    schedule 22.12.2013
comment
@bluesm: Мой ответ помог?   -  person Martin R    schedule 26.12.2013
comment
@MartinR Ага. Огромное спасибо!   -  person Paul Brewczynski    schedule 12.01.2014


Ответы (1)


Прежде всего, сильные указатели не могут использоваться в C-структурах, как объясняется в «Переходе к ARC Release Notes», поэтому массив объектов должен быть объявлен как

__unsafe_unretained  id __objects[MAX_STACKBUFF_SIZE];

если вы компилируете с помощью ARC.

Теперь это не очевидно (для меня) из NSFastEnumeration документации, но это объясняется в Какао с любовью: реализация countByEnumeratingWithState: objects: count:, при которой реализация не должна заполнять предоставленный массив объектов, а может просто установить __enumState.itemsPtr в существующий массив (например, некоторое внутреннее хранилище). В этом случае содержимое массива __objects не определено, что вызывает сбой.

Замена

id obj = __objects[i];

by

id obj = __enumState.itemsPtr[i];

дает ожидаемый результат, который вы наблюдали.

Еще одну ссылку можно найти в Пример кода" FastEnumerationSample ":

При реализации этого метода у вас есть два варианта:

1) Используйте массив на основе стека, предоставленный stackbuf. Если вы это сделаете, вы должны уважать значение len.

2) Верните свой собственный массив объектов. Если вы это сделаете, верните полную длину возвращаемого массива, пока у вас не закончатся объекты, а затем верните 0. Например, реализация связанного массива может возвращать каждый массив по порядку, пока вы не выполните итерацию по всем массивам.

В любом случае state->itemsPtr ДОЛЖЕН быть допустимым массивом (не равным нулю). ...

person Martin R    schedule 22.12.2013