5

我找到了这个答案:

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,我发现我的 __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;

当我尝试获取 __object 数组的内容时,我得到了 EXC_BAD_ACESS。我还发现,当您尝试遍历 __enumState.itemsPtr 时,它确实有效。

你能解释一下这里发生了什么吗?为什么我的__objects似乎被“缩小”了。为什么它不包含所需的对象?以及为什么在打开 ARC 时会出现该错误。

非常感谢您的时间和精力!(我提供了屏幕截图以便更好地了解导致错误的原因)

4

1 回答 1

3

首先,强指针不能在 C 结构中使用,如“过渡到 ARC 发行说明”中所述,因此对象数组已声明为

__unsafe_unretained  id __objects[MAX_STACKBUFF_SIZE];

如果你用 ARC 编译。

现在从文档中(对我来说)并不明显NSFastEnumeration,但在Cocoa With Love:Implementing countByEnumeratingWithState:objects:count: 中解释了实现不需要填充提供的对象数组,但可以设置 __enumState.itemsPtr为现有数组(例如一些内部存储)。在这种情况下, __objects数组的内容是未定义的,这会导致崩溃。

更换

id obj = __objects[i];

经过

id obj = __enumState.itemsPtr[i];

给出预期的结果,这就是你观察到的。

另一个参考可以在“FastEnumerationSample”示例代码中找到:

实现此方法时有两种选择:

1)使用stackbuf提供的基于堆栈的数组。如果你这样做,那么你必须尊重'len'的价值。

2) 返回您自己的对象数组。如果这样做,则返回返回的数组的全长,直到用完对象,然后返回 0。例如,链接数组实现可能会按顺序返回每个数组,直到您遍历所有数组。

在任何一种情况下,都state->itemsPtr必须是一个有效的数组(非零)。...

于 2013-12-22T00:22:47.943 回答