Autolayout и программные ограничения: как бороться с updateConstraints стрельбы несколько раз?

При программном создании макетов я следую рекомендациям Apple: переопределять -updateConstraints, добавлять пользовательские ограничения и вызывать -setNeedsUpdateConstraints после того, как в представлении добавлены субвью. Моя типичная настройка выглядит так:

- (void)setupViews
{
    //Style View

    //Add gesture recognizers

    //Add Subviews


    [self setNeedsUpdateConstraints];
}

- (void)updateConstraints
{
    //Add custom constraints       

    [super updateConstraints];
}

Проблема

Есть случаи, когда -updateConstraints запускается несколько раз (например, когда контроллер представления представлен или помечен w/animation). Проблема здесь в том, что каждое добавленное ограничение добавляется повторно. Это становится серьезной проблемой при попытке по требованию изменить константу добавленного ограничения, так как есть два первоначальных ограничения, которые впоследствии конфликтуют друг с другом. Я предполагаю, что даже когда вы не манипулируете ограничениями после их создания, удваивайте то, что вам кажется нехорошим.

Потенциальные решения

1 - Удалите все ограничения, влияющие на представление перед их применением в -updateConstraints:

 - (void)updateConstraints
    {   
        //Remove all constraints affecting view & subviews

        //Add custom constraints

        [super updateConstraints];       
    }

2 - Установите флаг макета и проверьте его перед добавлением пользовательских ограничений:

- (void)updateConstraints
{
    if (self.didAddConstraints) {
        [super updateConstraints];
        return;
    }

    //Add custom constraints   

    self.didAddConstraints = YES;    

    [super updateConstraints];
}

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

3 - Что-то удивительное, о котором я не думал.


Какая самая лучшая практика здесь?

Ответ 1

Короткий ответ: Потенциальное решение № 2.

Удаление и повторное использование всех ограничений может стать дорогостоящим, поскольку компоновка становится более сложной. Кроме того, если ваш макет имеет состояние, у вас будет больше проблем.

Ограничения удвоения очень неэффективны, вы никогда не знаете, сколько раз может быть вызвано updateConstraints.

Как этот отчет в блоге показывает, что использование флага - это самый простой и эффективный способ решения этой проблемы. Вот как я сам справляюсь с этим.

Как примечание, вы упоминаете о существовании удивительного способа, о котором вы еще не думали. В большинстве случаев самый простой способ - самый удивительный способ.:)

Ответ 2

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

override func updateConstraints() {
            if constraints.count == 0 {
                let views = ["textField": textField]
                addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[textField]-0-|", options: [], metrics: nil, views: views))
                addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[textField]-0-|", options: [], metrics: nil, views: views))
            }
            super.updateConstraints()
        }