Где инициализировать пользовательский UIView, созданный в интерфейсе Builder?

У меня есть подкласс UIView, который создается в XIB файле. Мне нужно, чтобы он выполнял некоторую инициализацию (настройки некоторых переменных и создание подвью).

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

Мой назначенный инициализатор initWithValues:.

Возникает вопрос: Где выполнить инициализацию?

Поскольку я должен выполнить его в двух разных местах, я решил, что мне нужно реорганизовать его в отдельный метод initialize (или что-то в этом роде) и вызвать его из initWithValues:.

Но при загрузке из IB вызываются как initWithCoder:, так и awakeFromNib. Из какого метода мне нужно позвонить initialize? Или мне нужно вызвать initWithValues: из initWithCoder: и ничего не делать в awakeFromNib?

Ответ 1

Вы должны использовать initWithFrame: при инициализации представлений (поскольку это назначенный инициализатор). Следовательно, если у вас initWithValues: убедитесь, что вы вызываете initWithFrame: из него.

Что-то вроде этого должно работать для инициализации:;)

- (void)initialize{
     //init your ivars here
}

- (id)initWithCoder:(NSCoder *)aCoder{
    if(self = [super initWithCoder:aCoder]){
        [self initialize];
    }
    return self;
}

- (id)initWithFrame:(CGRect)rect{
    if(self = [super initWithFrame:rect]){
        [self initialize];
    }
    return self;
}

Я собирался добавить еще одно объяснение, но ответ mplappert достаточно ясен. При необходимости используйте awakeFromNib.

Ответ 2

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

Ответ 3

К сожалению, в приведенных выше ответах не учитываются эти вещи: - (void) awakeAfterUsingCoder - и тот факт, что он вызвал после того, как что-то создается кодером (один раз для каждого представления Xib). Я вижу, что awakeFromNib страдает от той же судьбы. (Причина, по которой я нашел это)

Другая проблема с инициализацией заключается в том, что для пользовательских представлений можно избежать использования initWithCoder и initWithFrame. И если они называются, ленивая загрузка (хотя и не такая важная для самих представлений) означает, что вы "можете" изменить значения. Я считаю, что сделал это в initWithCoder, но если вы затем инициализируете значения в awakeFromNib, оно отменяется хотя бы один раз.

Я дошел до:

- (void) awakeFromNib (or didMoveToSuperView);
{
    BOOL called = NO;
    if(!called)
    {
    called = YES;
    }

}

Другой метод, который я использую, - просто вызвать требуемый инициализатор, затем вызвать мой собственный класс или инициализатор, соответствующий суперклассу.

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

Стив