Всегда ли указатели всегда указывают на объявление?
Я нашел разных людей/статей (например, этот ответ 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 "инициализирован", но который, и что мы называем третьим вариантом?
Ответы
Ответ 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 :
Успешное тестирование