2015-02-16 2 views
2

Обычный способ инициализироваться и выделить в Objective-C являетсяПочему я не должен выделять alloc и init?

NSObject *someObject = [[NSObject alloc] init]; 

Почему следующее не практикуется?

NSObject *someObject = [NSObject alloc]; 
[someObject init]; 
+4

им угадать, потому что вы не можете сделать что-нибудь полезное с не-inited объекта, так почему отдельные звонки вне дома? в качестве альтернативы вы можете просто перейти на [NSObject new]; 'который является удобным методом для выделения и инициализации – Fonix

ответ

8

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

init является особенным во многих классах, поскольку он может просто освободить приемник и вместо этого создать новый объект, который находится на другом адресе. Таким образом, ваш someObject указывает на неправильный (неинициализированный) экземпляр.

Существует много классов фреймворка, в которых используются аргументы метода init, чтобы решить, какой именно специализированный подкласс лучше всего использовать. Это часто случается с кластерными кластерами, такими как NSString или NSArray, но это действительно может случиться с каждым видом объекта.

Место, где вы можете увидеть это специальное поведение инициализаторов, ARC: It explicitly declares that the init family of methods eats up the receiver and returns a +1 retained object. Это не было бы необходимо, если инициализаторы всегда возвращали получателя.

Конечно, вы могли бы исправить свой код, просто делая другое назначение:

NSObject *someObject = [NSObject alloc]; 
someObject = [someObject init]; 

Это исправить эту проблему. Но и в этом нет никакого смысла.

1

Потому что он менее прост и подвержен ошибкам.

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

В отдельных строках нет никаких веских оснований для alloc и init, и по многим причинам против этого.

4

От объекта Initialization чиновника documentation:

Поскольку INIT ...метод может возвращать ноль или объект, отличный от явно выделено, это опасно использовать экземпляр, возвращаемый Alloc или allocWithZone: вместо одного возвращенного инициализаторе

Еще одна причина из того же документа заключается в том, что:

После того, как объект инициализируется, вы не должны инициализировать его снова

дал этот пример:

NSString *aStr = [[NSString alloc] initWithString:@"Foo"]; 
aStr = [aStr initWithString:@"Bar"]; 

где:

второй инициализации в этом примере, может привести к NSInvalidArgumentException поднимается.

+0

. Приобретено для цитирования документации по этой теме. –

0

По моему разумению выделенный объект не имеет смысла без его инициализации,

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

Пример:

NSString *str = [NSString alloc]; 
// Override point for customization after application launch. 
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 
NSLog(@"%ld",str.length); 

Когда я запускаю приведенный выше код я получаю это в моей консоли

Did you forget to nest alloc and init? 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!' 

, если я бы ниже, я бы до сих пор получить исключение, как ул не инициализируется, поскольку все, что инициализируется, не потребляется или не заостряется на странице

[str init]; 

Поэтому, если вы хотите сделать это в двух строках должно быть, как это

NSObject *someObject = [NSObject alloc]; 
someObject = [someObject init]; 

Но это всегда лучше держать их вложенная

NSObject *someObject = [[NSObject alloc]init]; 

Если вы планируете делать это на одной линии, а затем использовать ключевое слово new, которое поддерживает назначение и инициализацию в одной строке.

Пример:YourClass *object_ofClass = [YourClass new];

+1

В вашем примере проблема заключается не в отсутствии инициализации. Вы можете вставить строку '[myDict init];' перед 'NSLog' и все равно получить то же исключение. Ошибка возникает из объекта, возвращаемого из 'alloc'. Это простой «NSDictionary», который никогда не используется в кластере классов. –

+0

@NikolaiRuhe благодарит за это – NSDumb

Смежные вопросы