Pau*_*ski 5 objective-c foundation fast-enumeration for-in-loop ios
我找到了这个答案:
其中介绍了如何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];
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,我发现它错了.
首先,当您启用自动引用计数(ARC)时,您会收到错误消息
Sending '__strong id *' to parameter of type '__unsafe_unretained_id*' changes retain/release properties of pointer

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

这是实际代码(我假设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;
Run Code Online (Sandbox Code Playgroud)
当我尝试获取__object数组的内容时,我得到了EXC_BAD_ACESS.我还发现当你尝试迭代__enumState.itemsPtr它实际上是有效的.
你能解释一下这里发生了什么吗?为什么我__objects似乎"萎缩".为什么它不包含所需的对象?当ARC打开时,为什么会出现这种错误.
非常感谢您提前花时间和精力!(我提供了截图,以便更好地了解导致错误的原因)
首先,强指针不能在 C 结构中使用,如“过渡到 ARC 发行说明”中所述,因此对象数组已声明为
__unsafe_unretained id __objects[MAX_STACKBUFF_SIZE];
Run Code Online (Sandbox Code Playgroud)
如果你用ARC编译。
现在,从文档中(对我来说)并不明显,但在Cocoa With Love:Implementing countByEnumerateWithState:objects:count:NSFastEnumeration中解释了
该实现不需要填充提供的对象数组,而只需设置
为现有数组(例如一些内部存储)。在这种情况下,数组的内容
是未定义的,这会导致崩溃。__enumState.itemsPtr__objects
更换
id obj = __objects[i];
Run Code Online (Sandbox Code Playgroud)
经过
id obj = __enumState.itemsPtr[i];
Run Code Online (Sandbox Code Playgroud)
给出了预期的结果,这就是您观察到的结果。
另一个参考可以在“FastEnumerationSample”示例代码中找到:
实现此方法时您有两种选择:
1)使用stackbuf提供的基于堆栈的数组。如果您这样做,那么您必须尊重“len”的值。
2) 返回您自己的对象数组。如果执行此操作,请返回所返回数组的完整长度,直到用完对象为止,然后返回 0。例如,链接数组实现可能会按顺序返回每个数组,直到迭代所有数组为止。
无论哪种情况,
state->itemsPtr都必须是有效的数组(非零)。...