Interface Builder — візуальний редактор інтерфейсів, вбудований в Xcode для iOS та macOS розробки. Дозволяє створювати UI через drag-and-drop, налаштовувати Auto Layout, підключати код через IBOutlet та IBAction. Розберемо, як працює IB, чим відрізняються Storyboard та XIB, і навіщо потрібні @IBDesignable.
Головне
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.
До Xcode 4 Interface Builder був окремим додатком, що запускався паралельно з редактором коду. У Xcode 4 (2011) Apple об'єднала IB та редактор коду в єдину IDE. Це дозволило перемикатися між кодом та версткою без перемикання вікон, а також бачити зміни властивостей у реальному часі через панель Attributes Inspector.
| Версія Xcode | Рік | Зміни в Interface Builder |
|---|---|---|
| Xcode 3 | 2008 | IB — окремий додаток, підтримка iOS 2.0 |
| Xcode 4 | 2011 | IB вбудовано в IDE, з'явилися Storyboard |
| Xcode 5 | 2013 | Auto Layout з меню констрейнтів, прев'ю екранів |
| Xcode 6 | 2014 | Size Classes, @IBDesignable, Preview Assistant |
| Xcode 11 | 2019 | SwiftUI Canvas, IB залишається для UIKit |
| Xcode 15 | 2023 | SwiftUI Preview як основний інструмент, IB legacy-режим |
З появою SwiftUI у 2019 році Apple змістила фокус на декларативну розробку, однак Interface Builder залишається вбудованим у Xcode для підтримки UIKit-проєктів. Тисячі існуючих додатків продовжують використовувати IB, і Apple не оголошувала про його видалення.
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-файли легше мержити, вони компактніші та завантажуються швидше, оскільки не містять опису всього додатка.
| Критерій | Storyboard | XIB |
|---|---|---|
| Область | Кілька екранів + переходи | Один екран або компонент |
| Segues | Підтримує (push, modal, unwind) | Не підтримує |
| Merge в git | Складний (один великий XML) | Простий (багато маленьких файлів) |
| Завантаження | При старті додатка | На вимогу (ліниве) |
| Повторне використання | Тільки через storyboard references | Високе (комірки, хедери, в'ю) |
| Рекомендація Apple | Не рекомендується для великих проєктів | Рекомендується для компонентів |
З версії Xcode 11 Apple рекомендує використовувати XIB для окремих компонентів та уникати монолітних Storyboard. Для навігації між екранами краще використовувати кодову навігацію через UIStoryboardSegue (k) вручну або координатори.
Файли .storyboard та .xib зберігають XML у форматі Interface Builder Cocoa Touch XIB (dt). Приклад спрощеної структури:
<!-- 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 — система позиціонування елементів на екрані через математичні відношення (констрейти). 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 — абстракція, що групує пристрої за шириною та висотою екрана: Compact та Regular. Комбінації (wC hR для iPhone портретний, wR hR для iPad) дозволяють задавати різні констрейти та розташування елементів під різні сценарії. В Interface Builder перемикання між size classes змінює набір активних констрейнтів на канві.
| Пристрій | Орієнтація | Width Class | Height Class |
|---|---|---|---|
| iPhone (крім Max/Plus) | Портрет | Compact | Regular |
| iPhone (крім Max/Plus) | Ландшафт | Compact | Compact |
| iPhone Plus/Max | Ландшафт | Regular | Compact |
| iPad | Будь-яка | Regular | Regular |
| iPad Split View | 1/3 екрана | Compact | Regular |
Приклад констрейнту з варіацією за size class:
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 через інспектор, а код використовується для динамічних сценаріїв, які неможливо описати статично.
Зв'язок між візуальним інтерфейсом в 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).
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 — анотація Swift, що дозволяє відображати кастомну UIView прямо на канві Interface Builder у реальному часі. Розробник бачить результат змін коду без запуску додатка. @IBInspectable — анотація для властивостей, що додає їх у панель Attributes Inspector IB, де можна змінювати значення інтерактивно.
Ці анотації особливо корисні при створенні бібліотек UI-компонентів: кастомні кнопки, поля введення з маскою, анімовані індикатори. IBDesignable використовує prepareForInterfaceBuilder() (fn) для окремої компіляції коду збірки, що не зачіпає основний бінарник додатка.
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.
Процес трансформації файлів 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). Процес завантаження включає:
awakeFromNib() (fn) для кожного об'єкта — точка входу для пост-завантажувального налаштуванняМетод awakeFromNib() (fn) викликається після того, як всі IBOutlet вже встановлені, але до першого layoutSubviews. Це зручно для початкової конфігурації: встановлення заокруглень, додавання тіней, локалізації тексту. Однак всі IBOutlet вже гарантовано не nil в awakeFromNib.
З виходом 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 у реальному часі |
| Підтримка версій iOS | iOS 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 року.
Багаторічний досвід 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, tintColorIdentifier (k) кожному констрейнту в Size Inspector — це допомагає в дебазі при конфліктах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 — візуальний редактор для UIKit з форматом Storyboard/XIB, що працює через drag-and-drop. SwiftUI Preview — декларативне прев'ю в реальному часі, де інтерфейс описується кодом Swift. Обидва інструменти вбудовані в Xcode, але IB генерує XML, а SwiftUI компілює Swift напряму. IB підтримує iOS 2.0+, SwiftUI — iOS 13+.
Ні, Interface Builder несумісний зі SwiftUI напряму. SwiftUI використовує власний декларативний синтаксис та Canvas Preview. Однак UIKit-проєкти, створені через IB, можна інтегрувати в SwiftUI через UIViewRepresentable, а SwiftUI-в'ю вбудовувати в UIKit через UIHostingController. Це дозволяє поступово мігрувати з IB на SwiftUI.
@IBDesignable — анотація Swift, яка відображає кастомну UIView прямо в Interface Builder у реальному часі без запуску додатка. @IBInspectable — анотація для властивостей, що додає їх у панель Attributes Inspector IB. Обидві анотації пришвидшують розробку кастомних UI-компонентів: достатньо змінити властивість в інспекторі — зміна одразу видна на канві.
Auto Layout в Interface Builder задає констрейти через меню Pin (відступи, ширина, висота) та Align (центрування, baseline). Кожен констрейнт — математичне відношення між в'ю. IB відображає помилки червоними лініями, конфлікти — жовтими попередженнями. Size Classes в IB дозволяють задавати різні констрейти для різних пристроїв та орієнтацій без написання коду.
IBOutlet — анотація для посилання на UI-елемент з коду (наприклад, @IBOutlet weak var label: UILabel!). IBAction — анотація для методу, що викликається при події (наприклад, @IBAction func buttonTapped(_ sender: UIButton)). Зв'язок створюється через Ctrl+drag з канви IB у файл контролера. Xcode автоматично генерує код з'єднання при відпусканні миші.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.