2

私が書いた列挙子で奇妙なバグに出くわしました:

// 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:、最初の反復の直後に終了します。詳細に調べると、前の反復でパラメーターが YESに設定されるとすぐにstop初期化されるようになりました。これを修正するには、ストップ変数を意図的に初期化する必要があります。YES*stopNO

どうすればいいの?stop 変数のアドレス (おそらく偶然) は、「古い」値がそこにあることを説明する呼び出し全体で同じままである可​​能性があることを知っています。しかし、ARC は初期化されていない型がそれぞれ 0 に設定されていることを保証するという印象を受けていたnilので、関数が呼び出されるたびに BOOL を NO に設定すべきではありませんか?

興味深いことに、__block BOOL stop;stop 変数を使用すると、デバッガーによると、初回であっても常にYES に初期化されます (これも、初期化されていない値がそのアドレスにあった場合は、おそらく偶然です)。

これは、初期化されていない変数がゼロであり、ARC であると誤って想定している可能性があることを示しているようです。おそらく、ARC はオブジェクト型を nil で初期化することだけを気にし、整数型は気にしませんか? それとも、これは ivar にのみ当てはまり、ローカル変数には当てはまりませんか?

4

1 に答える 1

6

Objective-C オブジェクトへのポインターのみがnilARC (およびオブジェクトのすべてのインスタンス変数) で初期化されますが、ローカル変数は一般的に初期化されません。したがって、ブール変数を初期化する必要があります

BOOL stop = NO;
于 2013-10-09T15:23:01.033 に答える