Яблоки говорят, что:
назначенный инициализатор Иници ...
метод с первичной ответственностью
для инициализации новых экземпляров
учебный класс. Каждый класс определяет или наследует
его собственный назначенный инициализатор.
Посредством сообщений для себя, других
init ... методы в одном классе
прямо или косвенно ссылаться на
назначенный инициализатор, и
назначенный инициализатор, через
сообщение супер, вызывает
назначенный инициализатор его
суперкласс. [emp добавлено]
В принципе, указанный инициализатор - это тот метод init, который вызывают все другие методы init. Однако это не единственный метод инициализации. Также не каждый класс должен иметь свой собственный. На практике чаще всего назначаемый инициализатор - это суперкласс init.
Основная функция initWithCoder
- разрешить инициализацию из заархивированного объекта. В случае класса, который требует определенных данных, назначенный инициализатор примет эти данные. initWithCoder
затем просто распаковывает архив и затем вызывает назначенный инициализатор.
Например, назначенный инициализатор для UIView - initWithFrame:
. Итак, UIView initWithCoder
выглядит примерно так:
- (id)initWithCoder:(NSCoder *)decoder{
CGRect theFrame= //...uppack frame data
self=[self initWithFrame:theFrame];
return self;
}
Задача назначенного инициализатора состоит в том, чтобы создать центральную точку, через которую должна пройти вся инициализация, чтобы гарантировать полную инициализацию каждого экземпляра независимо от того, откуда поступили данные или от обстоятельств инициализации.
Это никогда не должно означать, что у класса может быть только один метод инициализатора.
Edit01
Из комментариев:
В частности, как передать значения
для некоторых из моих иваров, когда
инициализация происходит через
initWithCoder
Ну, нет. Весь смысл initWithCoder в том, что вы имеете дело с замороженным экземпляром вашего класса, который содержит все данные, необходимые для воссоздания объекта.
Протокол NSCoding заставляет ваш класс вести себя как креветки с рассолом, которые они продают как "Морские обезьяны" в комиксах. Методы кодирования обезвоживают / замораживают, высушивают рассол-креветку / экземпляры. Методы декодирования увлажняют рассол-креветку / экземпляры так же, как заливка рассола-креветки в воду. Так же, как у рассола-креветки есть все, что им нужно для начала жизни, кроме воды, кодированный объект, сохраненный на диске, содержит все данные, необходимые для воссоздания себя после инициализации с помощью кодера.
Каноническим примером этого является файл пера. Nib-файл - это просто набор «заморозки» элементов UI и контроллеров. UIViewController и его UIViews в nib-файле содержат все данные, необходимые для инициализации, в кодировке xml файла nib-файла. Когда вы вызываете initFromNib
напрямую или с помощью IBOutlet, он вызывает метод intiWithCoder:
каждого класса.
Если вы не сохраняете весь объект, когда вы его замораживаете, то атрибуты, которые не сушатся, не нужны для существования объекта экземпляра. *
Вы просто устанавливаете эти вспомогательные атрибуты после инициализации объекта.
Чтобы встроить указанный инициализатор, вы просто сначала декодируете, а затем вызываете назначенный инициализатор. Вот так:
-(id) initWithRequiredValue:(id) someValue otherRequiredValue:(id) anotherValue{
if (self=[super init]){
self.requiredProperty=someValue;
self.anotherRequiredProperty=anotherValue
}
return self;
}
Если суперкласс не поддерживает NSCoder, вы сами запускаете его в подклассе:
- (id)initWithCoder:(NSCoder *)decoder {
id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
self=[self initWithRequiredValue:someDecodedValue otherRequiredValue:someOtherDecodedValue];
return self;
}
Это самый простой случай. Если super сам поддерживает NSCoding, то обычно вы просто пишете параллельный назначенный инициализатор, например:
- (id)initWithCoder:(NSCoder *)decoder {
if (self=[super initWithCoder:decoder]){
id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
self.requiredProperty=someDecodedValue;
self.anotherRequiredProperty=someOtherDecodedValue;
}
return self;
}
Я думаю, что в большинстве случаев initWithCoder
оказывается параллельным назначенным инициализатором, потому что он заботится обо всей инициализации точно так же, как и назначенный инициализатор. Он не похож на назначенный инициализатор, потому что все его данные предоставляются кодером, но он выполняет ту же функцию.
Это один из тех случаев, когда теория и практика плохо сочетаются. Концепция «назначенного инициализатора» действительно применима только к случаям, когда вы создаете экземпляры с нуля.