【问题标题】:ObjC: Local variable seems to retain its value across function callsObjC:局部变量似乎在函数调用中保留其值
【发布时间】:2023-04-07 16:12:01
【问题描述】:

我刚刚在我写的枚举器中偶然发现了一个奇怪的错误:

// 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 初始化 stop 变量来解决这个问题。

这怎么可能?我知道停止变量的地址(可能是偶然的)在调用中可能保持不变,这可以解释“旧”值的存在。但是我的印象是ARC确保未初始化的类型分别设置为0nil,所以每次调用函数时不应该将BOOL设置为NO吗?

有趣的是,如果我使用__block BOOL stop;,则停止变量会根据调试器始终初始化为 YES,即使是在第一次时也是如此(同样,可能是偶然的,这取决于当时的未初始化值地址)。

这似乎表明我可能错误地假设未初始化的变量是零和 ARC——也许 ARC 真的只关心用 nil 初始化对象类型而不关心整数类型?或者这仅适用于 ivars 而不是局部变量?

【问题讨论】:

  • 正如 Martin R 在他的回答中提到的,需要初始化变量。至于为什么它似乎在没有(重新)初始化的情况下保留其值,可能只是您在调用树的同一级别调用方法(not 函数),并且因此局部变量在堆栈上被分配了与之前相同的插槽。结果:它“看到”了与上次调用时相同的值。

标签: objective-c automatic-ref-counting scope objective-c-blocks enumeration


【解决方案1】:

只有指向 Objective-C 对象的指针才使用 ARC 初始化为 nil (以及对象的所有实例变量),但通常不是局部变量。 所以你必须用

初始化布尔变量
BOOL stop = NO;

【讨论】:

  • 感谢您的确认,我想我最好重新检查一下我的代码是否有其他可能未初始化的非 ID 类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 2022-01-24
  • 1970-01-01
相关资源
最近更新 更多