Почему я должен выделять/инициировать экземпляры класса перед присвоением значений свойствам объектов?

Тупой пример, относящийся к тому, что мне интересно... Итак, у меня есть собственный класс, и я объявляю экземпляр класса.

Мой пользовательский класс *objectA;

objectA.property = значение;

ЕСЛИ Я NSLog(@"выведите значение: %@", objectA.property);

он вернет ноль.

ТЕПЕРЬ, ЕСЛИ я объявил это как таковое... MyCustomClass *objectA = [MyCustomClass alloc] init];

а затем присвоить ему значение...

objectA.property = значение;

Все как по маслу...

В конечном счете, мне интересно, почему X-Code не будет автоматически создавать экземпляр объекта в памяти, когда видит, что я назначаю его свойства в коде. С точки зрения разработчика лучше, чтобы он не делал этого за меня.


person Wade Sellers    schedule 15.11.2014    source источник
comment
Это не имеет ничего общего с Xcode. Все дело в том, как работает Objective-C во время выполнения.   -  person rmaddy    schedule 16.11.2014


Ответы (3)


Ответ Тома объясняет, почему среда выполнения не может безопасно создать для вас инициализирующий объект.

Следующий момент заключается в следующем: Objective-C ничего не делает для вас, «потому что он может сказать, что должен». Автоматической магии не существует. Если вам нужен объект, вы создаете инициализацию объекта. Если вы этого не сделаете, указатель равен нулю.

Компиляторы становятся умнее, это правда, но такое поведение типа «вы, должно быть, хотели создать объект, поэтому я просто молча сделаю это за вас» будет означать, что вы, программист, не можете точно сказать, что происходит. на.

Некоторые (интерпретируемые) языки 4-го поколения настраивают это для вас, но я не могу придумать ни одного скомпилированного языка/языка 3-го поколения, который это делает.

person Duncan C    schedule 16.11.2014
comment
И есть еще один хороший момент, который я тоже начал придумывать... Если бы компилятор начал делать предположения, мы бы нашли слишком много трещин в коде, потому что мы просто думали, что компилятор позаботится об этом за меня. Именно эти жесткие правила иногда позволяют нам проводить отладку намного быстрее, потому что правила, по которым нужно играть, иногда ужесточены. Хотя кажется, что всегда есть исключения из каждого правила, но я думаю, что на моем младшем уровне здесь просто знать правила важнее, чем то, как их нарушить и при этом иметь работающий код. Спасибо, что нашли время, Дункан! -Уэйд - person Wade Sellers; 16.11.2014

Интересно, почему X-Code не будет автоматически создавать экземпляр объекта в памяти, когда он увидит, что я назначаю его свойства в коде.

Потому что, как правильно создать экземпляр MyCustomClass? Часто достаточно alloc и init экземпляра, как в вашем примере кода. Но во многих случаях это привело бы к поломке, неработоспособности объектов из-за того, что не был вызван назначенный инициализатор. Например, если бы MyCustomClass был подклассом NSManagedObject, простой вызов init дал бы вам бесполезный объект.

В Swift классы могут различать назначенные и удобные инициализаторы, но это все равно не делает безопасным автоматическое создание экземпляров объектов, как вы описываете. Назначенные инициализаторы обычно существуют, потому что вы должны предоставить один или несколько аргументов инициализатору, чтобы он работал правильно. Например, что, если бы объект был NSString? Вы можете позвонить alloc и init, чтобы получить его, но это почти всегда неправильно. Какие аргументы следует использовать при автоматическом создании экземпляра объекта? Ни Xcode, ни Clang не могут этого знать, как и среда выполнения Objective-C.

person Tom Harrington    schedule 16.11.2014
comment
Вы делаете большое замечание... Точно так же, как вы можете действительно захотеть сделать что-то вроде... NSArray *array = [NSArray alloc] initWithObjects:‹#(id), ...#›, nil]; Это хорошее объяснение. Спасибо, что нашли время. - person Wade Sellers; 16.11.2014

Уже много хороших ответов. Вот еще один ракурс.

Когда вы пишете:

MyCustomClass *objectA;

Что вы говорите компилятору, так это то, что objectA — это имя места в памяти — адрес — где вы ожидаете хранить объект класса MyCustomClass. На самом деле вы еще не создали такой объект.

Вы можете поместить экземпляр MyCustomClass по этому адресу, создав новый с alloc/init. Но на данный момент вам это не нужно, и компилятор не может предположить, что вы это сделаете. С таким же успехом вы можете получить его откуда угодно — вызвав какой-нибудь другой метод в каком-то другом классе, который возвращает MyCustomClass, или вытащите его из массива и т. д.

Поскольку у вас еще нет объекта — только место для него, — попытка установить для него свойство не даст результата. Итак, когда вы звоните

objectA.property = value;

В настоящее время objectA равно nil — ничему, пустому адресу. Одно из правил ObjC заключается в том, что когда вы пытаетесь что-то сделать, ничего не происходит, и вы ничего не получаете взамен. (Время от времени эта функция может быть полезна, а в других — разочаровывать.) Так что эта строка не работает.

person rickster    schedule 16.11.2014
comment
Это лучший ответ, потому что он не предполагает, что OP понимает разницу между объявлением типа указателя для объекта и выделением памяти для объекта. (Я думаю, что это источник путаницы для него/нее.) - person Aky; 16.11.2014
comment
Это сделало это! Большое спасибо. Да, точно! Когда вы пытаетесь что-то сделать, ничего не происходит, и вы ничего не получаете взамен. Это, конечно, может иногда разочаровывать. Мой учитель здесь, в Mobile Makers, дал мне хорошее правило, которому я должен следовать, пока я продвигаюсь вперед. Во-первых, я создам экземпляр своего объекта локально и выделю/инициализирую в методе по мере необходимости, чтобы я мог видеть все, что происходит вместе. Спасибо, что нашли время ответить. Он очень ценит это! ржу не могу. - person Wade Sellers; 17.11.2014