Подтвердить что ты не робот

Что такое _UITemporaryLayoutWidth и почему он нарушает мои ограничения?

У меня есть раскадровка с Autolayout и классами размера. Довольно сложный макет, и, к сожалению, я не могу точно определить, как воспроизвести проблему в новом проекте.
Но рассматриваемая точка привязана к левому и правому краю экрана с ограничением, которое имеет приоритет 750 (т.е. |-([email protected])-[myView]-([email protected])-|, дополнительно имеет большее или равное ограничение с приоритетом 1000 (т.е. |-(>=0)-[myView]-(>=0)-|)). Это делается для ограничения ширины на iPad, поэтому существует ограничение ширины width <= 600 @1000, а также горизонтальное положение по горизонтали в контейнере. Кроме того, представление имеет ограничение соотношения сторон 3: 1. Поскольку я сказал, довольно сложный.

Интерфейс Builder не обнаруживает проблем с ограничениями. Предварительный просмотр макета Xcode корректен для всех устройств.

Когда я запускаю приложение, iOS говорит мне, что у него конфликтующие ограничения.

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7fd72853ff80 DMXKit.DipSwitchAssembly:0x7fd72990d0e0.width == 3*DMXKit.DipSwitchAssembly:0x7fd72990d0e0.height>",
    "<NSLayoutConstraint:0x7fd728574e50 '_UITemporaryLayoutWidth' H:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(400)]>",
    "<NSLayoutConstraint:0x7fd72856e9c0 V:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(133)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7ffb19798000 DMXKit.DipSwitchAssembly:0x7ffb1979a000.width == 3*DMXKit.DipSwitchAssembly:0x7ffb1979a000.height>

Это повторяется пару раз, с теми же (то есть, с теми же указателями) ограничениями. Это тоже странно, похоже, что ограничение не нарушено. При запуске приложение выглядит на 100% правильным. Когда я смотрю приложение в отладчике представления Xcode, ограничение с адресом 0x7ffb19798000 все еще существует, поэтому оно никогда не прерывалось.

Откуда возникает константа _UITemporaryLayoutWidth? Очевидно, я не добавил его. Google не плюет ничего полезного в _UITemporaryLayoutWidth. Кто-нибудь сталкивался с такой проблемой?

4b9b3361

Ответ 1

Итак, я не уверен, что это поможет вам справиться с вашей проблемой, поскольку похоже, что вы создаете свой макет в IB, но здесь проблема, с которой я столкнулся, может помочь другим, которые ищут google для "_UITemporaryLayoutWidth",

Мой сценарий заключался в том, что я добавлял автоматические ограничения компоновки во время init и случайно запускал "layoutIfNeeded" перед добавлением представления в иерархию представлений (изменение макетов триггеров вставки кромок кнопок). Похоже, система добавляет эти временные ограничения и (предположим?) Удаляет их после добавления представления в иерархию. Ограничения temp задают 0 измерений (в моем случае), которые могут завершиться неудачей, если вы, например, задаете в своем макете конкретные значения констант ограничения (например, вы хотите 16px между этими кнопками, но там 0 пробелов в этом измерении...)

Обновление: Изучено немного больше и выяснилось, что временное ограничение соответствует кадру, который используется для инициализации родительского представления. В моем случае используемым фреймом был размер 0x0, поэтому ограничение temp оценивалось относительно размера 0x0, таким образом, сбой. Проверено, что если я инициализирую с помощью кадра 5x5, то я вижу ту же ошибку с ограничением _UITemporaryLayoutWidth (5). Другая вещь, которую я заметил, заключается в том, что ограничение, по-видимому, добавляется и удаляется во время оценки компоновки - если я сломаюсь до того, как я запустим макет и проанализирую ограничения, то я не вижу ограничений временного диапазона. Я также не вижу ограничений после ошибки, поэтому я подозреваю, что они синтезируют временные ограничения, добавляют их, решают, а затем удаляют их.

Обновление 2: Хорошо, возможно, это TMI, но это может кому-то помочь. Моя нынешняя мысль заключается в том, что эти временные ограничения - это взгляд на то, как система обрабатывает смешанное управление кадрами и автоопределение внутри одной иерархии представлений. В моем случае у моего представления не было родителя и не было ограничений, определяющих его размер, но у него был нулевой кадр, что означало, что система предполагала, что размер он должен использовать при решении макета. Моя мысль состоит в том, что система синтезирует эти временные ограничения для представлений, у которых их фреймы заданы явно для решения остальной части системы при ее перемещении по иерархии.

Обновление 3: Итак, я снова столкнулся с этой проблемой и хотел поделиться немного дополнительной информацией. Мой сценарий состоял в том, что я пытался по существу измерить представления, у которых не было родителя, использующего метод systemLayoutSizeFittingSize:. Короче говоря, мне пришлось вызвать layoutIfNeeded в представлении перед его измерением - вот где я столкнулся с конфликтом с временными ограничениями, поскольку в представлении нет супервизора. Константы ограничения времени (размеры) соответствуют какому-либо фрейму на представлении без супервизора - я думаю, что это имеет смысл (хотя установка кадра на представление, которое вы собираетесь использовать с AutoLayout, кажется странным...) Я смог обойти проблему ограничения тем, сказав: если в представлении нет супервизора, добавьте его во временный супервизор; измерения; удалите его из временного супервизора. Надеюсь, это полезно.

Ответ 2

Как упоминалось выше, временные ограничения, по-видимому, устанавливаются в представлениях, которые не имеют родительского представления. Я обнаружил, что обеспечение translatesAutoresizingMaskIntoConstraints false в представлении верхнего уровня устраняет временные ограничения. В:

topView.translatesAutoresizingMaskIntoConstraints = false

Ответ 3

В моем случае проблема заключалась в следующем:

Я создал UIButton.
Я установил ограничения ширины и высоты. Я добавил кнопку в свой список.
Я установил свои ведущие и верхние ограничения компоновки в супервизор.

Это создало ошибку "Unable to simultaneously satisfy constraints", и одним из конфликтующих ограничений было _UITemporaryLayoutHeight.

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

Ответ 4

Корень проблемы - это соотношение сторон 3: 1. Если я изменю его на что-то другое, он работает, теперь я использую 4:1.4, который работает. Я не знаю почему, но это работает.

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

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

Ответ 5

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

Ответ 6

В моей ситуации, я только получил этот конфликт UITemporaryLayoutWidth в этой ситуации 1 Я создаю представление с [UIView new], и я не добавлял его в какой-либо супервизор 2, тогда я создаю ограничение ширины, чтобы этот вид был просто создан 3 invoke layoutIfNeeded к этому представлению немедленно, и конфликт происходит

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