Подтвердить что ты не робот

Всегда ли указатели всегда указывают на объявление?

Я нашел разных людей/статей (например, этот ответ SO), предполагая, что значение указателей в Objective-C не определено, пока вы не присвоите ему что-то, Тем не менее, я нахожу на практике, что они автоматически устанавливаются на nil еще до того, как я вызываю alloc - для меня следующий код работает без утверждения:

NSString* foo;          // 1
assert(foo==nil);       // foo is nil
foo = [NSString alloc]; // 2
assert(foo!=nil);       // after alloc, not nil.
foo = [foo init];       // 3
assert(foo!=nil);       // still not nil

Можно ли/полагаться на это? Является ли это гарантией или я просто запускаю свой компилятор (Xcode) в каком-то режиме отладки? (Я новичок в Objective-C).

Следственный вопрос: какова правильная терминология для описания foo в состоянии в конце строк, помеченных 1, 2 и 3? Я предполагаю, что хотя бы один из 1 и 2 их именуется "неинициализированным", а один из 2 и 3 "инициализирован", но который, и что мы называем третьим вариантом?

4b9b3361

Ответ 1

В ARC при инициализации все указатели объектов устанавливаются на nil. Если он не работает под управлением ARC или при использовании указателей на другие типы данных, неинициализированный указатель будет иметь значение мусора (и, по сути, чтение из указателя вызывает поведение undefined в соответствии со стандартом C).


@Chuck указывает на что-то важное, а это касается только локальных переменных. Любая переменная со статическим хранилищем (статистическая статистика или глобальные переменные) и переменные экземпляра всегда инициализируются соответствующим нулевым значением (которое для указателей составляет nil/NULL).

Ответ 2

(Для ARC см. ответ Кевина)

Можно ли/полагаться на это?

Нет - никогда не полагайтесь на это. В случае отладочной сборки (в зависимости от настроек вашего компилятора) память стека обычно обнуляется. Если включена оптимизация, компилятор не делает этого для вас, и вам будут присвоены значения мусора, основанные на том, что произошло в последней области стека.

Вы можете полагаться на обнуленные ivars в инициализаторах объектов.

Вы можете защитить себя от статического анализатора и включив -Wuninitialized для своих конфигураций сборки, когда уровень оптимизации больше, чем -O0.

Следственный вопрос: какова правильная терминология для описания foo в состоянии в конце строк с отметками 1, 2 и 3? Я предполагаю, что хотя бы один из 1 и 2 их именуется "неинициализированным", а один из 2 и 3 "инициализирован", но который, и что мы называем третьим вариантом?

  • Uninitialized
  • Объект objc, который был выделен, но не был инициализирован (небезопасно использовать в противном случае)
  • Инициализированный экземпляр objc или объект.

Ответ 3

Ответ на ваш следственный вопрос:

После # 1 foo объявлен, но не инициализирован.

После # 2 foo был выделен, но все еще неинициализирован.

После # 3 инициализируется foo.

На практике вы никогда не хотите разделять шаги 2 и 3, то есть ваш код должен быть foo = [[NSString alloc] init]. Причина этого в том, что "опасно" выделять объект, а не инициализировать его, или инициализировать его ненадлежащим образом.

Если вы просто сделаете это foo = [NSString alloc], но забудьте когда-нибудь вызвать init, небезопасно использовать foo, поскольку он не был инициализирован. Точно так же небезопасно делать это [foo init] (обратите внимание на отсутствие переназначения на foo), поскольку init может возвращать другую ссылку на инициализированный объект, чем был первоначально выделен alloc.

Ответ 4

В объектах ARC Environment автоматически устанавливается значение nil. Но всегда рекомендуется применять Assign value для объектов во время инициализации.

Я только что проверил тест с obj-c в среде ARC

NSString *testStr ;
if (testStr == nil) {
    NSLog(@"Test Successful");
}

OutPut : Успешное тестирование

NSString *testStr = nil;
if (testStr == nil) {
    NSLog(@"Test Successful");
}

OutPut : Успешное тестирование