Connect with us

Разработка

Подходы к верстке в UIKit

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

Фото аватара

Опубликовано

/

     
     

Алексей Маринин, ведущий разработчик мобильных приложений в Озон, рассказывает про разные подходы к программированию интерфейсов в iOS-приложениях.

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

Прежде всего попробуем понять, что такое верстка и зачем она нам нужна:

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

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

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

  1. Storyboards/xib
  2. Autolayout
  3. Frame based layout

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

Interface builder

Представленная еще в iOS 5 технология, призванная значительно ускорить время разработки интерфейсов, некогда была очень популярна в коммерческих проектах, потому что действительно на первый взгляд сильно упрощает и ускоряет разработку простых программных интерфейсов.

Выглядит все следующим образом. Вам не нужно писать никакого кода, вы просто используете визуальный интерфейс и располагаете компоненты так, как вам это нужно.

Подходы к верстке в UIKit

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

Давайте попробуем это реализовать:

import UIKit

final class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!

    @IBAction func didTapButton(_ sender: UIButton) {
        button.backgroundColor = .random
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

Сверху представлен код, в котором реализована смена цвета кнопки при нажатии на нее. Для этого использован @IBOutlet, который держит ссылку на объект и позволяет нам его конфигурировать из кода. Также с помощью @IBAction реализована обработка нажатия. Когда пользователь нажимает на кнопку, программа видит, что в кнопке содержится ссылка на @IBAction и вызывает его.

Пока все выглядит потрясающе, давайте создадим merge request, чтобы наши коллеги тоже увидели как здорово и просто создавать интерфейсы, используя Interface Builder. Так будут выглядеть изменения в нашем ViewController.

Подходы к верстке в UIKit

Почему так? Дело в том, что Interface Builder сохраняет свои изменения в XML-формате, из-за чего их практически невозможно прочитать на код ревью, что сильно усложняет разработку. Так же, если одновременно 2 разработчика что-то поменяют на одном и том же экране, возникнет конфликт такой силы, что его скорее всего нельзя будет разрешить, не переделывая все заново.

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

Подходы к верстке в UIKit

Но, к сожалению, неопытный разработчик забывает переименовать класс внутри InterfaceBuilder. Что же произойдет?

  1. Компилятор выдаст ошибку?
  2. Отобразится пустой экран?
  3. Приложение упадет в рантайме?

Ответ ниже

Подходы к верстке в UIKit

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

Из-за чего это произошло? По сути, Interface Builder — это отдельное приложение внутри вашего Xcode, из-за этого и возникают такие критические и сложно прогнозируемые ошибки. И это далеко не единственный сценарий, когда выше приложение может прекратить работу из-за критической ошибки в самый неожиданный момент, также это может возникнуть из-за неправильных идентификаторов UITableViewCell, ошибках в идентификаторах segues и др.

Так же стоит отметить, что верстка через StoryBoard может значительно замедлять работу Xcode, особенно если вы используете атрибут @IBDesignable или у вас очень большой StoryBoard/xib.

Также стоит отметить, что не все параметры можно настроить из Interface Builder, что вынуждает разработчика настраивать представления на половину из кода, наполовину из IB, что очень сильно усложняет код и делает его не читаемым.

Давайте же подведем итоги:

Плюсы

  1. Легкий вход в технологию
  2. Действительно быстрая и простая верстка в сравнении с другими подходами
    • Вы мгновенно видите изменения в отображении, и если ваш проект компилируется очень медленно, это может существенно увеличить скорость разработки.
    • Вам не нужно читать код чтобы что-то изменить, все уже очень наглядно и просто отрисовано, выбирай нужный элемент с помощью мышки и изменяй как тебе нужно.

Минусы

  1. Сложно прогнозируемые ошибки в рантайме
  2. Невозможность проведения эффективного код ревью
  3. Xcode зависает
  4. Не такой гибкий как код, многие параметры невозможно настроить с помощью Interface Builder

Итог

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

AutoLayout

В настоящее время это наиболее распространенный тип верстки в мобильных приложениях.

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

При этом разработчику эти уравнения необходимо задавать вручную из кода, изменения возможно увидеть только при полном запуске приложения, что,  конечно, довольно серьезно замедляет разработку относительно использования сторибордов.

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

import UIKit

final class ViewController: UIViewController {
    private var button: UIButton?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        setupButton()
        setupButtonConstraints()
    }
    
    private func setupButton() {
        let button = UIButton()
        
        button.backgroundColor = .green
        button.setTitle("Change color", for: .normal)
        button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
        view.addSubview(button)
        
        self.button = button
    }
    
    private func setupButtonConstraints() {
        guard let button = button else { return }

        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: .zero),
            NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: .zero),
            NSLayoutConstraint(item: button, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50),
            NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
        ])
    }
    
    @objc private func didTapButton() {
        button?.backgroundColor = .random()
    }
}

На первый взгляд данный код выглядит намного больше (38 строчек против 12) и сложнее, чем при использовании сторибордов, но это только на первый взгляд.

Во-первых, у нас нет сториборда, и наши изменения в гите будут выглядеть вот так:

Подходы к верстке в UIKit

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

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

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

Итак, подводя итоги, можно сказать следующее:

Плюсы

  1. Отличная читаемость кода
  2. Относительная безопасность

Минусы

  1. В сравнении с storyboard сложнее вход в технологию
  2. Сложнее понимать код, требуется некоторая практика

Итог

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

Frame based layout

У первых мобильных устройств Apple было всего одно разрешение экрана (от самых первых iPhone вплоть до iPhone 4S), и поэтому перед разработчиками не стояла задача создавать адаптивные интерфейсы. Они просто вручную задавали координаты и размеры представлений на экране.

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

В чем же смысл использовать “верстку на фреймах” в современных iOS-приложениях? Все просто. Хоть AutoLayout гораздо современнее и удобнее, но считать размеры представлений вручную — гораздо быстрее для системы, чем решать систему линейных уравнений.

Что же она из себя представляет? По сути, мы просто сами в коде считаем размер наших представлений, а так же их координаты относительно друг друга. Давайте посмотрим, как бы выглядел наш экран, но на этот раз реализованный с использованием frame based layoud подхода:

import UIKit

final class ViewController: UIViewController {
    private var button: UIButton?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        setupButton()
    }
    
    private func setupButton() {
        let button = UIButton()
        
        button.backgroundColor = .green
        button.setTitle("Change color", for: .normal)
        button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
        view.addSubview(button)
        
        self.button = button
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        performLayout()
    }
    
    private func performLayout() {
        guard let button = button else { return }
        
        let buttonWidth: CGFloat = 185
        let buttonHeight: CGFloat = 54
        let buttonX = view.center.x - (buttonWidth / 2)
        let buttonY = view.center.y - (buttonHeight / 2)
        
        button.frame = CGRect(x: buttonX, y: buttonY, width: buttonWidth, height: buttonHeight)
    }
    
    @objc private func didTapButton() {
        button?.backgroundColor = .random()
    }
}

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

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

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

Подытожим про фреймы:

Плюсы

  1. Самая большая производительность

Минусы

  1. Значительно возрастает сложность разработки (соответственно уменьшается скорость)
  2. Сложные экраны становятся достаточно громоздкими

Итог

Frame based layout это отличный подход к разработке интерфейсов, он сильно производительнее других подходов.

Но использовать его нужно с осторожностью. Если у вас большое e-commerce приложение в поздней стадии разработки и каждый hitch (событие, когда 1 кадр на экране отрисовывается медленнее, чем частота обновления кадра устройства, и возникает подвисание) стоит вам миллионы рублей, вам целесообразнее использовать этот подход.

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

Сравнение разных подходов

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

  • Storyboards — дешевый в разработке, но у него большие проблемы с масштабированием.
  • AutoLayout — средний по разработке, у него нет проблем с масштабированием, но не самый производительный.
  • Manual based layout — самый производительный, нет проблем с масштабированием, но самый дорогой в разработке.
Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Advertisement

Наши партнеры:

LEGALBET

Мобильные приложения для ставок на спорт
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: