循环如何在内部工作 - 目标C - 基础

时间:2013-12-21 23:44:16

标签: ios objective-c foundation for-in-loop fast-enumeration

我找到了这个答案:

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

Screenshot of an error

但即使我关闭ARC,我发现__object数组似乎表现得很奇怪:

Screenshot of error2

这是实际代码(我假设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打开时,为什么会出现这种错误。

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

1 个答案:

答案 0 :(得分: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必须是有效的   数组(非零)。 ...