Примечание
Слова layout, autolayout и constraints я перевёл, соответственно, как вёрстка, автовёрстка и ограничения.
Работа с автовёрсткой
Проблемы автовёрстки решать непросто. Запуская приложение, надеешься, что все установленные ограничения работают корректно, а получаешь кучу ошибок автовёрстки в логах консоли.
Interface Builder неплох как визуальный редактор вёрстки. В нём есть индикация некорректных граничных параметров. Однако ваша вёрстка может отличаться от видимой в IB. На экран приложения могут влиять различные параметры — например, ответы на сетевые запросы или локально сохранённые данные. Более того, могут быть экраны, частично или полностью построенные на информации, заданной сервером. От сервера может поступать вообще всё что угодно, в том числе шрифты, цвета и формы.
Кажется, остаётся только вручную разбирать гигантский лог ошибок автовёрстки. Но есть и другие варианты. Например, сервис для начинающих WTFAutoLayout (WTF значит “Why The Failure”, т. е. «почему сломалось», а не то, о чём вы подумали), который переводит загадочные сообщения об ошибках в красивое визуальное представление проблемы.
Спасибо jpmmusic за этот сервис
Данный сервис — большой шаг вперёд. С ним куда легче находить проблемы заданных ограничений. Но он всё ещё вынуждает искать конфликтующие ограничения, писать фиксы, перезапускать приложение, переходить к определённому экрану и надеяться, что:
экран выглядит так же, как и во время ошибки;
установленная вёрстка совпадает с той, что была во время ошибки;\
ошибки автовёрстки действительно пропали.
Учитывайте, что состояние приложения могло измениться. Может быть, после перезапуска приложения ответ сервера изменился, и содержимое, которое вызывало ошибку, просто не поступило. Это может касаться, например, слишком длинных текстов в ячейках.
View Debugger + LLDB спешат на помощь
View Debugger в составе Xcode — это отличный инструмент, помогающий разобраться, из чего состоит пользовательский интерфейс и как отлаживать ошибки автовёрстки. Если вы никогда не пользовались View Debugger, я рекомендую посмотреть этот видеоролик с разбором интерфейса; в этой статье подробного руководства по View Debugger не будет.
Одна из мощных возможностей View Debugger — отображение предупреждений и ошибок вёрстки. Это сильно экономит время на поиск причин, вызывающих проблемы автовёрстки.
Теперь можно перейти к конфликтному экрану и прочитать описание ошибки на вполне человеческом языке: “Height and vertical position are ambiguous” («Высота и вертикальная позиция неоднозначны»). Перейдём к LLDB. Мы реализуем ключевую концепцию, представленную на WWDC 2018 под названием «Продвинутая отладка в Xcode и LLDB». Если вы её ещё не видели, я настоятельно рекомендую ознакомиться с ней.
Попробуем исправить ошибки вёрстки без перезапуска приложения и без перезагрузки текущего экрана. Этот подход сэкономит много времени и просто необходим, если воспроизвести ошибку вёрстки не получается.
Вот план:
Запустим View Debugger
Деактивируем ошибочное ограничение
Применим верное ограничение
Обновим вёрстку прямо из отладчика LLDB
Убедимся, что все ошибки и предупреждения автовёрстки пропали
ПРОФИТ
Подход будет продемонстрирован на очень простом одноэкранном приложении, но концепция легко переносится на любой экран, в том числе намного более сложный. Вот демокласс вьюконтроллера:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let colorView = UIView()
colorView.translatesAutoresizingMaskIntoConstraints = false
colorView.backgroundColor = .lightGray
view.addSubview(colorView)
NSLayoutConstraint.activate([
colorView.heightAnchor.constraint(greaterThanOrEqualToConstant: 277),
colorView.widthAnchor.constraint(equalToConstant: 242),
colorView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
colorView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
При запущенном приложении и активном экране симулятора делаем Alt+ЛКМ на иконке View Debugger:
Учтите, что симулятор должен быть активен, пока Xcode находится на заднем плане.
Alt+ЛКМ на кнопке, отмеченной на скриншоте выше, если симулятор находится на переднем плане, открывает View Debugger и оставляет приложение симулятора работающим. Этот трюк является важной частью нашего метода: так мы можем проверять обновления пользовательского интерфейса в реальном времени.
View Debugger открывается, а приложение остаётся в прерванном состоянии (на точке останова). Скопируйте конфликтующее ограничение (в примере view.height >= 277 @ 1000
) с помощью ⌘ C и перейдите в LLDB.
Перед действиями в LLDB может понадобиться импортировать UIKit. Выполните следующую команду: expr @import UIKit
.
Это копирование поместит в буфер обмена адрес ограничения с приведением типа в таком формате: ((NSLayoutConstraint *) 0x600002a01810. Теперь его можно использовать, чтобы деактивировать ограничение:
e ((NSLayoutConstraint *)0x600002a01810).active = false;
Чтобы посмотреть текущее состояние вашего макета после деактивации ограничения, запустите e [CATransaction flush]
на LLDB, и вы увидите изменения, отражённые в симуляторе (это сработает, потому что симулятор остаётся активным на переднем плане).
Теперь мы можем применить ограничение, которое, предположительно, решит нашу проблему. Надо скопировать экран из View Debugger, как уже сделали с ограничением, и добавить явное ограничение к экрану:
e [(NSLayoutDimension *)[((UIView *)0x7fac3d7060b0) heightAnchor] constraintEqualToConstant: 277].active = YES;
Выполните e [CATransaction flush];
ещё раз, чтобы убедиться, что теперь вёрстка верна, и нажмите на кнопку play/pause рядом с кнопкой «активировать все точки останова»: приложение в симуляторе продолжит работу.
Чтобы убедиться, что новое ограничение не вызывает новых проблем с макетом, снова откройте View Debugger. Система ещё раз проверит, есть ли новые предупреждения Auto Layout. Как можно видеть, их нет.
Вот и всё. В несколько простых шагов вы нашли конфликтующее ограничение, протестировали исправление и убедились, что предупреждения автовёрстки исчезли; приложение даже не пришлось перезапускать.
LLDB поддерживает псевдонимы и сценарии: советую рассмотреть этот функционал, поскольку он ускоряет отладку. Начать можно здесь.
awoland
Ответьте пожалуйста, зачем к статье с исходным кодом на ЯП Swift "лепить" тег другого ЯП objective-c ?
ws233 Автор
Потому что это работает и на ObjC. Если внимательно присмотритесь, то команды дебагеру даются и на ObjC тоже. Собственно, от языка это не зависит. На мой взгляд, изначальная реализация кода никак не влияет на то, о чем говорится в статье, и ребятам, пишущим на ObjC, это будет не менее полезно. Извините, если это потревожило вашу ленту и вам это не нужно.