我刚刚在我写的枚举器中偶然发现了一个奇怪的错误:
// typedef for reference
typedef void (^OGWEntityEnumerationBlock)(OGWEntity* entity, BOOL* stop);
-(void) enumerateEntitiesInCategory:(const OGWEntityCategory*)category
usingBlock:(OGWEntityEnumerationBlock)block
{
BOOL stop;
NSArray* entitiesInCategory = [_cagetorizedEntities objectForKey:category];
for (OGWEntity* entity in [entitiesInCategory reverseObjectEnumerator])
{
block(entity, &stop);
if (stop)
{
break;
}
}
}
第一次使用enumerateEntitiesInCategory:usingBlock:
工作正常。最终,调用方找到它正在搜索的实体,并将*stop
参数设置为 YES
。
enumerateEntitiesInCategory:usingBlock:
的下一次使用在第一次迭代后立即退出。经过仔细检查,stop
现在初始化为YES
,只要上一次迭代将*stop
参数设置为 YES。我必须有目的地用NO
初始化停止变量来解决这个问题。
这怎么可能?我知道停止变量的地址(也许是偶然的(可能在调用中保持不变,这可以解释那里的"旧"值。但我的印象是 ARC 确保未初始化的类型分别设置为 0 nil
,那么它不应该在每次调用函数时将 BOOL 设置为 NO 吗?
有趣的是,如果我使用__block BOOL stop;
则 stop 变量总是根据调试器初始化为 YES,即使在第一次也是如此(同样,可能是偶然的,具体取决于该地址上的任何未初始化值(。
这似乎表明我可能错误地假设未初始化的变量是零和 ARC——也许 ARC 真的只关心用 nil 初始化对象类型而不关心整型类型?还是这只适用于 ivars 而不是局部变量?
只有指向 Objective-C 对象的指针被初始化为 nil
(以及对象的所有实例变量(,但一般不是局部变量。所以你必须
BOOL stop = NO;