Вопрос

Примечание:Я относительно новичок в 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, но поскольку это немного утомительно, я хотел бы хотя бы знать, почему я это делаю.

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

Спасибо!

Это было полезно?

Решение

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

Причина, по которой NeXT отошла от соглашения Stepstone об использовании сообщения +new (которое было идеей 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:), которые сделают все три шага за вас.

Редактировать:Дополнительную информацию по этой теме, включая важные идеи комментаторов, можно найти в моем сообщении в блоге «воссоединение”.

Видеть NSZone.

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

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

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

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

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

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


(c) Шаблоны проектирования какао Эрика М.Бак и Дональд А.Яктман

Вам не обязательно.Вы можете использовать [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 и initwithdata... :Выделенная память инициируется желаемыми данными в соответствии со свойствами класса.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top