Interface Builder — визуелни уређивач интерфејса уграђен у Xcode за iOS и macOS развој. Омогућава креирање UI-ја путем drag-and-drop, подешавање Auto Layout-а, повезивање кода преко IBOutlet и IBAction. Анализираћемо како IB ради, по чему се Storyboard и XIB разликују и чему служе @IBDesignable.
Главно
Interface Builder — компонента Xcode-а намењена визуелном пројектовању корисничких интерфејса. Историја IB-а почела је 1988. године у компанији NeXT, много пре појаве iOS-а. Стефан Поуп је развио прву верзију за 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) | Не подржава |
| Спајање у 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 омогућава постављање подразумеваних вредности за сваки 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-у, што ће изазвати пад при приступу — зато се IBOutlet декларише као weak var (k s) са implicit unwrap.
@IBDesignable — Swift анотација која омогућава приказ прилагођеног UIView-а директно на IB платну у реалном времену. Програмер види резултат промена кода без покретања апликације. @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+ |
| Спајање у 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-у. Ово олакшава спајање, убрзава учитавање и омогућава поновну употребу компоненти између пројеката кроз 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
}
}Пример приказује најбољу праксу за 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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође