Почему в Objective-C аллок и init называются отдельно?

Примечание: я относительно новичок в Objective-C и исхожу из Java и PHP.

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

Не может ли это быть сделано в таких методах инициализации:

+ (MyClass*)init {
    MyClass *instance = [MyClass alloc];
    [instance setFoo:@"bla"];

    return instance;
}

+ (MyClass*)initWithString:(NSString*)text {
    MyClass *instance = [MyClass init];
    [instance setFoo:text];

    return instance;
}
...

это просто реликт из старых дней C или есть что-то, что я не вижу?

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

Мне нравится выразительность языка до сих пор, но это то, что я хочу полностью понять, чтобы мыслить объективно-С.

спасибо!

7 ответов


+ new завершает отправку сообщения + alloc классу и сообщения-init на все, что возвращается из +alloc.

причина, по которой NeXT отступил от соглашения Stepstone об использовании +new message (что было идеей Smalltalk), заключается в том, что на раннем этапе они столкнулись с ситуациями, когда они хотели иметь возможность инициализировать один и тот же объект более одного раза.


потому что создание экземпляра и инициализация экземпляра-это два отдельных задания.

отправить alloc сообщение классу для получения неинициализированного экземпляра. Затем вы должны инициализировать экземпляр, и у вас часто есть несколько способов сделать это. Например:

myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:@"%@.%@", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];

каждый из них инициализирует строку совершенно по-разному. Как вы инициализируете строку, зависит от того, из чего вы хотите ее инициализировать.

конечно, никто не любит пишу alloc а то init а то autorelease каждый раз, поэтому у вас обычно есть удобные методы (например,stringWithFormat:), которые делают все три шага для вас.

Edit: для получения дополнительной информации по этой теме, включая основные идеи от комментаторов, см. мой блог"воссоединение".


посмотреть NSZone.

+alloc это сокращение для +allocWithZone:, который является механизмом, обеспечивающим оптимизацию распределения памяти.

Итак, у вас есть возможность сделать что-то вроде этого:

foo = [[NSString allocWithZone:MyZone] initWithString:@"Foo"];
foo2 = [foo copyWithZone:MyZone];

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

для того, чтобы зонирование было эффективным вы бы хотели иметь +allocWithZone: доступно для каждого подкласса NSObject, поэтому вам нужно отделить выделение и инициализацию. Вы можете создавать и использовать все ярлыки, которые вы хотите, как +new, но под ним все, что вам понадобится -init метод, который инициализирует объект, который уже был выделен.


" разделение этапов выделения и инициализации создания экземпляра дает много преимуществ. Можно использовать любую вариацию метода класса +alloc для выделения экземпляра, а затем использовать любой доступный инициализатор с новым экземпляром.Это позволяет создавать собственные методы инициализации без необходимости предоставления альтернативных реализаций всех методов распределения. Новые методы распределения редко создаются, так как существующие методы удовлетворяют почти всем необходимость. Однако почти для каждого класса создаются один или несколько новых инициализаторов. Из - за разделения этапов выделения и инициализации реализации инициализаторов должны иметь дело только с переменными новых экземпляров и могут полностью игнорировать проблемы округления выделения.Разделение упрощает процесс написания инициализаторов. Кроме того, стандартные инициализаторы Cocoa, такие как-initWithCoder: работают с экземплярами независимо от способа выделения памяти для экземпляра. Один отрицательным следствием разделения распределения и инициализации является необходимость знать о таких соглашениях, как назначенный инициализатор.Необходимо знать, какие методы назначаются инициализаторами и как создавать и документировать новые инициализаторы в подклассах. В долгосрочной перспективе использование назначенных инициализаторов упрощает разработку программного обеспечения, но есть аргумент, что двухэтапный шаблон создания добавляет кривую раннего обучения для разработчиков Cocoa."


(с) шаблоны проектирования какао Эрик М. бак и Donald Yacktman А.


вы не должны. Вы можете использовать [MyClass new]. Это похоже на ваш гипотетический init метод.

В принципе, Objective-C, который изначально не имел сборки мусора, разделяет концепцию выделения памяти и инициализации класса. Вот почему существуют два различных метода. Когда вы звоните alloc, вы явно выделяете память.


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

для NSString у вас есть, например:

+ (id)string  // (Empty string)
+ (id)stringWithFormat:...  // Formatted string (like you use)
+ (id)stringWithContentsOfURL:... // String populated with contents of URL

и так далее. И вы бы использовали это как:NSString *myString = [NSString stringWithFormat:@"Hello %@\n", userName];

большинство других классов имеют это, как Списка NSArray:

+ (id)array
+ (id)arrayWithContentsOfFile:...
+ (id)arrayWithContentsOfURL:...
+ (id)arrayWithObjects:...

вам просто нужно читать документацию. :) И читать другие ответы о том, почему вы не хотите использовать это слишком много.


alloc: память выделяется / предоставляется объекту-ссылке. Теперь ссылка обладает памятью, но еще ничего не сделала. Эта память будет пустой (редчайший случай) или с некоторыми анонимными данными.

alloc и init : выделенная память очищается/опорожняется. Память инициируется нулевым битом.

alloc и initwithdata...: выделенная память инициируется с требуемыми данными, относящимися к свойствам класс.

например, когда вы покупаете участок, вы получаете владение. Этот участок дан вам так, как он есть, разрушенные кирпичи или старый дом могут быть там. Это alloc.

когда вы очищаете свой участок и удаляете всю грязь и мусор. Это alloc с init.

когда вы строите это в какой-то ценный дом, он становится более значимым для вас. И это alloc initwith...