Interface Builder: що це, візуальний дизайн у Xcode та сторіборди

Автор: IT Sectr Опубліковано: 2026-02-12 Час читання: 15 хв

Interface Builder — візуальний редактор інтерфейсів, вбудований в Xcode для iOS та macOS розробки. Дозволяє створювати UI через drag-and-drop, налаштовувати Auto Layout, підключати код через IBOutlet та IBAction. Розберемо, як працює IB, чим відрізняються Storyboard та XIB, і навіщо потрібні @IBDesignable.

Головне

  • Interface Builder — візуальний редактор у Xcode для UIKit-інтерфейсів без написання коду верстки
  • Storyboard описує кілька екранів та переходи між ними; XIB — один компонент або екран
  • Auto Layout в IB задає констрейти через меню Pin, Align та Resolve Issues
  • IBOutlet та IBAction пов'язують код Swift з UI-елементами через Ctrl+drag
  • @IBDesignable та @IBInspectable відображають кастомні в'ю прямо на канві IB

Що таке Interface Builder?

Interface Builder — компонент Xcode, призначений для візуального проєктування користувацьких інтерфейсів. Історія IB почалася ще в 1988 році в компанії NeXT, задовго до появи iOS. Стефан Поп (Stefan Pope) розробив першу версію для NeXTSTEP — операційної системи, що стала основою macOS та iOS. У 1996 році Apple придбала NeXT та інтегрувала Interface Builder в Xcode.

У сучасному Xcode Interface Builder підтримує три формати файлів: Storyboard (сторіборди), XIB (Xcode Interface Builder) та XIB-файли для табличних комірок та кастомних в'ю. Кожен із цих форматів зберігає XML-опис ієрархії UI-елементів, їхніх властивостей, констрейнтів та зв'язків із кодом.

IB працює на рівні UIKit: кнопки, лейбли, текстові поля, таблиці, колекції та констрейти перетягуються мишею на канву. Xcode компілює .storyboard та .xib файли в nib-архіви (compiled Interface Builder) на етапі збірки, що зменшує розмір бандла та пришвидшує завантаження.

За даними Apple, понад 70% iOS-проєктів на UIKit використовують Interface Builder на різних етапах розробки. Незважаючи на зростання SwiftUI, IB залишається стандартом для комерційних додатків із підтримкою iOS 12 та нижче, а також для складних кастомних інтерфейсів, що вимагають тонкого налаштування Auto Layout.

Як Interface Builder потрапив до Xcode

До Xcode 4 Interface Builder був окремим додатком, що запускався паралельно з редактором коду. У Xcode 4 (2011) Apple об'єднала IB та редактор коду в єдину IDE. Це дозволило перемикатися між кодом та версткою без перемикання вікон, а також бачити зміни властивостей у реальному часі через панель Attributes Inspector.

Версія XcodeРікЗміни в Interface Builder
Xcode 32008IB — окремий додаток, підтримка iOS 2.0
Xcode 42011IB вбудовано в IDE, з'явилися Storyboard
Xcode 52013Auto Layout з меню констрейнтів, прев'ю екранів
Xcode 62014Size Classes, @IBDesignable, Preview Assistant
Xcode 112019SwiftUI Canvas, IB залишається для UIKit
Xcode 152023SwiftUI Preview як основний інструмент, IB legacy-режим

З появою SwiftUI у 2019 році Apple змістила фокус на декларативну розробку, однак Interface Builder залишається вбудованим у Xcode для підтримки UIKit-проєктів. Тисячі існуючих додатків продовжують використовувати IB, і Apple не оголошувала про його видалення.

Storyboard та XIB: формати файлів IB

Interface Builder підтримує два основні формати: Storyboard (.storyboard) та XIB (.xib). Різниця між ними — в області видимості та сценарії використання.

Storyboard — файл, що містить всю сцену додатка: кілька екранів (UIViewController), переходи між ними (segues), навігаційні контролери, таб-бари та всі UI-елементи. Storyboard завантажується один раз при запуску з Info.plist через ключ UIMainStoryboardFile (k). Це зручно для візуалізації потоку екранів, але створює проблеми при merge-конфліктах у git, оскільки XML-опис всього додатка зберігається в одному файлі.

XIB (розшифровується як Xcode Interface Builder) — файл для одного компонента: окремої UIView, UITableViewCell, UICollectionViewCell або одного ViewController. XIB завантажується на вимогу через UINib(nibName:bundle:) (k) або метод Bundle.loadNibNamed (k). XIB-файли легше мержити, вони компактніші та завантажуються швидше, оскільки не містять опису всього додатка.

КритерійStoryboardXIB
ОбластьКілька екранів + переходиОдин екран або компонент
SeguesПідтримує (push, modal, unwind)Не підтримує
Merge в gitСкладний (один великий XML)Простий (багато маленьких файлів)
ЗавантаженняПри старті додаткаНа вимогу (ліниве)
Повторне використанняТільки через storyboard referencesВисоке (комірки, хедери, в'ю)
Рекомендація AppleНе рекомендується для великих проєктівРекомендується для компонентів

З версії Xcode 11 Apple рекомендує використовувати XIB для окремих компонентів та уникати монолітних Storyboard. Для навігації між екранами краще використовувати кодову навігацію через UIStoryboardSegue (k) вручну або координатори.

Структура XML в IB-файлах

Файли .storyboard та .xib зберігають XML у форматі Interface Builder Cocoa Touch XIB (dt). Приклад спрощеної структури:

xml
<!-- XIB-файл з UIView та UILabel -->
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB"
          version="3.0">
  <objects>
    <view id="abc-123"
          userLabel="CustomHeaderView"
          contentMode="scaleToFill">
      <subviews>
        <label id="def-456"
               text="Заголовок"
               textColor="darkTextColor"
               fontDescription="title1"/>
      </subviews>
    </view>
  </objects>
</document>

Кожен елемент має унікальний id (an), за яким IB пов'язує XML-вузол із runtime-об'єктом. При компіляції Xcode перетворює XML на бінарний nib-формат (.nib), зменшуючи розмір файлу приблизно на 40%.

Auto Layout та Size Classes в Interface Builder

Auto Layout — система позиціонування елементів на екрані через математичні відношення (констрейти). Interface Builder надає візуальний інтерфейс для створення, редагування та налагодження констрейнтів без написання коду. Кожен констрейнт описує залежність: view.leading = superview.leading + 16 (k) або view.width = 2 * otherView.height (k).

В IB констрейти створюються через меню Pin (закріплення відступів, ширини, висоти) та Align (вирівнювання по центру, краях, baseline). Панель Size Inspector показує всі констрейти вибраного елемента, їхні пріоритети (required/high/low) та дозволяє редагувати мультиплікатори та константи.

IB також підтримує UIStackView — контейнер, що автоматично керує розташуванням дочірніх в'ю. Достатньо помістити елементи в stack view на канві, і IB згенерує необхідні констрейти автоматично. Це значно пришвидшує верстку порівняно з ручним розставленням констрейнтів.

Size Classes: адаптація під пристрої

Size Classes — абстракція, що групує пристрої за шириною та висотою екрана: Compact та Regular. Комбінації (wC hR для iPhone портретний, wR hR для iPad) дозволяють задавати різні констрейти та розташування елементів під різні сценарії. В Interface Builder перемикання між size classes змінює набір активних констрейнтів на канві.

ПристрійОрієнтаціяWidth ClassHeight Class
iPhone (крім Max/Plus)ПортретCompactRegular
iPhone (крім Max/Plus)ЛандшафтCompactCompact
iPhone Plus/MaxЛандшафтRegularCompact
iPadБудь-якаRegularRegular
iPad Split View1/3 екранаCompactRegular

Приклад констрейнту з варіацією за size class:

swift
import UIKit

class AdaptiveViewController: UIViewController {

    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var leadingConstraint: NSLayoutConstraint!

    private func updateConstraints() {
        let isRegular = traitCollection.horizontalSizeClass == .regular
        leadingConstraint.constant = isRegular ? 40 : 16
        titleLabel.font = isRegular
            ? UIFont.preferredFont(forTextStyle: .largeTitle)
            : UIFont.preferredFont(forTextStyle: .title1)
    }

    override func traitCollectionDidChange(
        _ previousTraitCollection: UITraitCollection?
    ) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
            updateConstraints()
        }
    }
}

У коді вище traitCollectionDidChange реагує на зміну size class, оновлюючи констрейнт та шрифт. Interface Builder дозволяє задати default-значення для кожного size class через інспектор, а код використовується для динамічних сценаріїв, які неможливо описати статично.

IBOutlet, IBAction та зв'язок коду з UI

Зв'язок між візуальним інтерфейсом в Interface Builder та кодом Swift/Objective-C здійснюється через два механізми: IBOutlet (Interface Builder Outlet) та IBAction (Interface Builder Action). Обидва створюються перетягуванням із затиснутою клавішею Ctrl з канви IB у файл контролера.

IBOutlet — анотація, що оголошує посилання на UI-елемент. Xcode автоматично підключає її до відповідного об'єкта в nib-архіві при завантаженні. Якщо з'єднання обривається (наприклад, перейменовано елемент), додаток падає з помилкою NSUnknownKeyException (k). IBOutlet позначається як weak (k), оскільки nib володіє об'єктом, а контролер — лише спостерігач.

IBAction — метод, що викликається при події UI-елемента: натискання кнопки, зміна тексту, перемикання світчера. IB пов'язує UIControlEvent (k) з методом через addTarget:action:forControlEvents: (k). У коді IBAction виглядає як звичайний метод з типом, що повертається IBAction (dt).

swift
import UIKit

final class LoginViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    @IBOutlet weak var spinner: UIActivityIndicatorView!

    @IBAction private func loginButtonTapped(_ sender: UIButton) {
        guard let email = emailTextField.text, !email.isEmpty,
              let password = passwordTextField.text, !password.isEmpty
        else {
            showAlert(message: "Заповніть всі поля")
            return
        }
        loginButton.isEnabled = false
        spinner.startAnimating()
        performLogin(email: email, password: password)
    }

    private func performLogin(email: String, password: String) {
        /// API-виклик через URLSession
        let request = LoginRequest(email: email, password: password)
        APIClient.shared.login(request) { [weak self] result in
            DispatchQueue.main.async {
                guard let self else { return }
                self.spinner.stopAnimating()
                self.loginButton.isEnabled = true
                switch result {
                case .success:
                    self.navigateToMainScreen()
                case .failure(let error):
                    self.showAlert(message: error.localizedDescription)
                }
            }
        }
    }

    private func showAlert(message: String) {
        let alert = UIAlertController(
            title: "Помилка",
            message: message,
            preferredStyle: .alert
        )
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        present(alert, animated: true)
    }
}

У прикладі показана стандартна зв'язка: IBOutlet для текстових полів, кнопки та спіннера, IBAction для обробки натискання. Всі ці зв'язки встановлюються в Interface Builder через Ctrl+drag. Якщо з'єднання не налаштоване, IBOutlet буде nil (v) при runtime, що викличе crash при зверненні — тому IBOutlet оголошується як weak var (k s) з implicit unwrap.

@IBDesignable та @IBInspectable: кастомні компоненти

@IBDesignable — анотація Swift, що дозволяє відображати кастомну UIView прямо на канві Interface Builder у реальному часі. Розробник бачить результат змін коду без запуску додатка. @IBInspectable — анотація для властивостей, що додає їх у панель Attributes Inspector IB, де можна змінювати значення інтерактивно.

Ці анотації особливо корисні при створенні бібліотек UI-компонентів: кастомні кнопки, поля введення з маскою, анімовані індикатори. IBDesignable використовує prepareForInterfaceBuilder() (fn) для окремої компіляції коду збірки, що не зачіпає основний бінарник додатка.

swift
import UIKit

@IBDesignable
final class GradientButton: UIButton {

    @IBInspectable var startColor: UIColor = .systemBlue {
        didSet { updateGradient() }
    }

    @IBInspectable var endColor: UIColor = .systemPurple {
        didSet { updateGradient() }
    }

    @IBInspectable var cornerRadius: CGFloat = 12 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = true
        }
    }

    private let gradientLayer = CAGradientLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupGradient()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupGradient()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
    }

    private func setupGradient() {
        layer.insertSublayer(gradientLayer, at: 0)
        updateGradient()
    }

    private func updateGradient() {
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setupGradient()
    }
}

У коді вище GradientButton — IBDesignable-компонент з IBInspectable-властивостями startColor (v), endColor (v) та cornerRadius (v). При перетягуванні UIView на канву IB та зміні класу на GradientButton в Identity Inspector, на канві відобразиться кнопка з градієнтом у реальному часі. Всі IBInspectable-властивості з'являться в панелі Attributes Inspector праворуч.

Важливо: @IBDesignable компілює код повністю для відображення в IB, тому всередині нього не повинні виконуватися мережеві запити або довгі операції. Для розмежування використовується #if TARGET_INTERFACE_BUILDER (k) — умовна компіляція, що виключає код, не призначений для IB.

Життєвий цикл IB-файлів при компіляції

Процес трансформації файлів Interface Builder від створення nib до відображення на екрані включає кілька етапів. Розуміння цього циклу допомагає діагностувати проблеми з IB.

На етапі збірки Xcode запускає інструмент ibtool (k, fn) — командну утиліту для компіляції .storyboard та .xib файлів у бінарний nib-формат. ibtool також виконує валідацію: перевіряє коректність констрейнтів, наявність всіх класів, типи з'єднань IBOutlet/IBAction. Помилки валідації відображаються в Issue Navigator Xcode.

Фінальний .nib-архів поміщається в бандл додатка в папку .nib (s). Розмір nib-файлу значно менший за вихідний XML: бінарний формат використовує оптимізоване представлення із заміною рядків на токени та стисненням числових значень. Типове стиснення — 50–60% від вихідного XML-розміру.

В runtime nib завантажується через UINib(nibName:bundle:) (k) або автоматично через UIStoryboard.instantiateViewController(withIdentifier:) (k). Процес завантаження включає:

  • Десеріалізація бінарного nib у граф об'єктів Objective-C/Swift
  • Створення екземплярів всіх UI-елементів з архіву
  • Відновлення зв'язків IBOutlet та IBAction (outletCollection для груп)
  • Застосування констрейнтів Auto Layout з архіву з урахуванням size class
  • Виклик awakeFromNib() (fn) для кожного об'єкта — точка входу для пост-завантажувального налаштування

Метод awakeFromNib() (fn) викликається після того, як всі IBOutlet вже встановлені, але до першого layoutSubviews. Це зручно для початкової конфігурації: встановлення заокруглень, додавання тіней, локалізації тексту. Однак всі IBOutlet вже гарантовано не nil в awakeFromNib.

Interface Builder проти SwiftUI Preview

З виходом SwiftUI у 2019 році у iOS-розробників з'явилася альтернатива Interface Builder — декларативний фреймворк з Canvas Preview у реальному часі. Розберемо ключові відмінності двох підходів.

Interface Builder генерує XML-опис, який компілюється в nib. Інтерфейс створюється візуально, код відповідає тільки за логіку. IB вимагає нижчого порогу входу для дизайнерів без навичок програмування, але складний у рев'ю коду (зміни XML не видно в diff).

SwiftUI Preview — повністю кодова розробка. Інтерфейс описується на Swift, прев'ю оновлюється при кожному збереженні. Немає XML, немає nib, немає ризику обриву з'єднань IBOutlet. SwiftUI Preview працює швидше за IB, оскільки не вимагає компіляції окремого файлу.

КритерійInterface Builder (UIKit)SwiftUI Preview
Формат файлуXML (.storyboard / .xib) → бінарний nibКод Swift (без проміжного файлу)
Прев'юКанва IB із затримкою при складних в'юCanvas Preview у реальному часі
Підтримка версій iOSiOS 2.0+ (всі версії)iOS 13+
Merge в gitПроблемний (один XML-файл)Простий (звичайний Swift-код)
Динамічні даніЧерез IBOutlet + код@State (k), @Observable (k)
Кастомні в'ю@IBDesignable (збірка)SwiftUI View з PreviewProvider
ПродуктивністьШвидке завантаження nibКомпіляція Swift на льоту

На практиці вибір між IB та SwiftUI Preview залежить від вимог проєкту. Interface Builder незамінний для UIKit-додатків з підтримкою старих iOS, а також для комерційних проєктів, де дизайнери працюють в Xcode без навичок Swift. SwiftUI кращий для нових проєктів, орієнтованих на iOS 17+, де важливі швидкість розробки та реактивність.

Apple не планує видаляти Interface Builder з Xcode. Більше того, в Xcode 16 компанія покращила продуктивність канви IB та додала підтримку SwiftUI-компонентів через UIViewRepresentable Bridge. Очікується, що IB підтримуватиметься ще щонайменше до 2030 року.

Кращі практики роботи з Interface Builder

Багаторічний досвід iOS-розробки сформував набір рекомендацій, що знижують кількість проблем при використанні Interface Builder у комерційних проєктах.

Використовуйте XIB замість Storyboard для компонентів багаторазового використання. Кожна кастомна комірка таблиці, хедер або футер повинні бути в окремому XIB. Це полегшує merge, пришвидшує завантаження та дозволяє перевикористовувати компоненти між проєктами через Swift Package Manager або CocoaPods.

Налаштовуйте Storyboard References для розбиття великих сторібордів на модулі. Замість одного Main.storyboard на 100 екранів створіть по сторіборду на кожен модуль (Auth, Profile, Feed) та зв'яжіть їх через Storyboard Reference. Це зменшить час компіляції ibtool та спростить командну роботу.

Уникайте IBOutlet-з'єднань до File's Owner (k) без перевірки. Кожне з'єднання повинно бути weak (k) та опціональним (implicitly unwrapped optional прекрасний тільки в playground). При перейменуванні IBOutlet у в'юсі Xcode автоматично оновлює з'єднання, але при ручному редагуванні XML легко припуститися помилки.

  • Завжди перевіряйте Show Connection Panel (k) після редагування IB-файлу — червоні індикатори вказують на обірвані з'єднання
  • Використовуйте User Defined Runtime Attributes (k) для встановлення властивостей без коду: layer.cornerRadius, layer.borderWidth, tintColor
  • Групуйте констрейти в IB за призначенням: констрейти для розмірів, констрейти для відступів, констрейти для співвідношень
  • Призначайте Identifier (k) кожному констрейнту в Size Inspector — це допомагає в дебазі при конфліктах
  • Не розміщуйте бізнес-логіку в awakeFromNib — тільки UI-конфігурацію. Логіку — в viewDidLoad або окремі сервіси
swift
import UIKit

final class ProfileHeaderView: UIView {

    @IBOutlet weak var avatarImageView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bioLabel: UILabel!
    @IBOutlet weak var editButton: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        avatarImageView.layer.cornerRadius = avatarImageView.bounds.width / 2
        avatarImageView.layer.masksToBounds = true
        nameLabel.font = UIFont.preferredFont(forTextStyle: .headline)
        bioLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
    }

    func configure(with profile: UserProfile) {
        nameLabel.text = profile.fullName
        bioLabel.text = profile.bio
        /// Завантаження аватара через SDWebImage або Kingfisher
    }

    static func instantiateFromNib() -> ProfileHeaderView {
        let nib = UINib(nibName: String(describing: self), bundle: nil)
        return nib.instantiate(withOwner: nil).first as! ProfileHeaderView
    }
}

У прикладі показана best practice для XIB-в'ю: статичний метод instantiateFromNib (fn) завантажує в'ю з XIB з тим самим ім'ям, що й клас. Метод awakeFromNib (fn) налаштовує UI (заокруглення, шрифти), а метод configure(with:) (fn) приймає модель даних для заповнення. Розділення відповідальності спрощує тестування та перевикористання.

Часті запитання

Чим Interface Builder відрізняється від SwiftUI Preview?

Interface Builder — візуальний редактор для UIKit з форматом Storyboard/XIB, що працює через drag-and-drop. SwiftUI Preview — декларативне прев'ю в реальному часі, де інтерфейс описується кодом Swift. Обидва інструменти вбудовані в Xcode, але IB генерує XML, а SwiftUI компілює Swift напряму. IB підтримує iOS 2.0+, SwiftUI — iOS 13+.

Чи можна використовувати Interface Builder з SwiftUI?

Ні, Interface Builder несумісний зі SwiftUI напряму. SwiftUI використовує власний декларативний синтаксис та Canvas Preview. Однак UIKit-проєкти, створені через IB, можна інтегрувати в SwiftUI через UIViewRepresentable, а SwiftUI-в'ю вбудовувати в UIKit через UIHostingController. Це дозволяє поступово мігрувати з IB на SwiftUI.

Що таке @IBDesignable та @IBInspectable?

@IBDesignable — анотація Swift, яка відображає кастомну UIView прямо в Interface Builder у реальному часі без запуску додатка. @IBInspectable — анотація для властивостей, що додає їх у панель Attributes Inspector IB. Обидві анотації пришвидшують розробку кастомних UI-компонентів: достатньо змінити властивість в інспекторі — зміна одразу видна на канві.

Як працює Auto Layout в Interface Builder?

Auto Layout в Interface Builder задає констрейти через меню Pin (відступи, ширина, висота) та Align (центрування, baseline). Кожен констрейнт — математичне відношення між в'ю. IB відображає помилки червоними лініями, конфлікти — жовтими попередженнями. Size Classes в IB дозволяють задавати різні констрейти для різних пристроїв та орієнтацій без написання коду.

Як пов'язувати код з Interface Builder через IBOutlet та IBAction?

IBOutlet — анотація для посилання на UI-елемент з коду (наприклад, @IBOutlet weak var label: UILabel!). IBAction — анотація для методу, що викликається при події (наприклад, @IBAction func buttonTapped(_ sender: UIButton)). Зв'язок створюється через Ctrl+drag з канви IB у файл контролера. Xcode автоматично генерує код з'єднання при відпусканні миші.

Підсумки

  • Interface Builder — візуальний редактор в Xcode для UIKit з історією з 1988 року (NeXTSTEP)
  • Storyboard підходить для прототипування, XIB — для компонентів багаторазового використання та production-проєктів
  • Auto Layout та Size Classes в IB дозволяють створювати адаптивні інтерфейси без коду
  • IBOutlet та IBAction пов'язують код з UI через Ctrl+drag з автоматичною генерацією Swift-властивостей
  • @IBDesignable та @IBInspectable пришвидшують розробку кастомних в'ю з прев'ю в IB
  • SwiftUI Preview витісняє IB для нових проєктів, але IB залишається стандартом для UIKit-легасі
  • Кращі практики: XIB замість Storyboard, weak IBOutlet, ідентифікація констрейнтів, розділення awakeFromNib та конфігурації

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також