iPhone & ndash; initWithCoder является исключением из обычного назначенного шаблона проектирования инициализатора?

Другая версия C # с ленивым поколением комбинационных индексов. Эта версия поддерживает единый массив индексов для определения сопоставления между списком всех значений и значениями для текущей комбинации, т. Е. Постоянно использует дополнительное пространство O (k) в течение всего времени выполнения. Код генерирует отдельные комбинации, включая первый, в O (k) времени.

public static IEnumerable<T[]> Combinations<T>(this T[] values, int k)
{
    if (k < 0 || values.Length < k)
        yield break; // invalid parameters, no combinations possible

    // generate the initial combination indices
    var combIndices = new int[k];
    for (var i = 0; i < k; i++)
    {
        combIndices[i] = i;
    }

    while (true)
    {
        // return next combination
        var combination = new T[k];
        for (var i = 0; i < k; i++)
        {
            combination[i] = values[combIndices[i]];
        }
        yield return combination;

        // find first index to update
        var indexToUpdate = k - 1;
        while (indexToUpdate >= 0 && combIndices[indexToUpdate] >= values.Length - k + indexToUpdate)
        {
            indexToUpdate--;
        }

        if (indexToUpdate < 0)
            yield break; // done

        // update combination indices
        for (var combIndex = combIndices[indexToUpdate] + 1; indexToUpdate < k; indexToUpdate++, combIndex++)
        {
            combIndices[indexToUpdate] = combIndex;
        }
    }
}

Код теста:

foreach (var combination in new[] {'a', 'b', 'c', 'd', 'e'}.Combinations(3))
{
    System.Console.WriteLine(String.Join(" ", combination));
}

Выход:

a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e
16
задан William Jockusch 31 May 2010 в 16:37
поделиться

1 ответ

Apples говорит, что:

назначенный инициализатор Метод init... метод, который несет основную ответственность за инициализацию новых экземпляров класса. Каждый класс определяет или наследует свой собственный назначенный инициализатор. Через сообщения к self, другие методы init... в том же классе прямо или косвенно вызывают назначенный инициализатор, а назначенный инициализатор, через сообщение super, вызывает назначенный инициализатор своего суперкласса. [emp added]

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

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

Например, назначенным инициализатором для UIView является initWithFrame:. Таким образом, initWithCoder UIView выглядит примерно так:

- (id)initWithCoder:(NSCoder *)decoder{
    CGRect theFrame= //...uppack frame data
    self=[self initWithFrame:theFrame];
    return self;
}

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

Это никогда не следует понимать как то, что класс может иметь только один метод инициализатора.

Edit01

Из комментариев:

В частности, как мне передать значения для некоторых моих иваров, когда инициализация происходит через initWithCoder?

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

Протокол NSCoding заставляет ваш класс вести себя подобно рассольным креветкам, которых в комиксах продают как "морских обезьян". Методы кодирования обезвоживают/замораживают/высушивают рассольные креветки/вещества. Методы декодирования гидратируют рассол креветок/вещества так же, как и заливка рассола креветок водой. Подобно тому, как у рассольных креветок есть все необходимое для начала жизни, кроме воды, закодированный объект, сохраненный на диске, имеет все данные, необходимые для воссоздания себя после инициализации кодером.

Каноническим примером этого является nib-файл. nib-файл - это просто куча сублимированных экземпляров элементов пользовательского интерфейса и контроллеров. 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;
}

Это самый простой случай. Если суперкласс сам поддерживает 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 оказывается параллельным назначенным инициализатором, потому что он берет на себя всю инициализацию, как и должен делать назначенный инициализатор. Он не выглядит как назначенный инициализатор, потому что все его данные предоставляются кодером, но он выполняет ту же функцию.

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

28
ответ дан 30 November 2019 в 21:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: