SwiftUI — декларативни оквир Apple-а за изградњу корисничких интерфејса на свим платформама екосистема, представљен на WWDC 2019. За разлику од императивног UIKit-а са viewDidLoad и ручним ажурирањем екрана, SwiftUI описује UI као колекцију једноставних структура које одговарају протоколу View. Према Swift.org (2025), SwiftUI се користи у 65% нових пројеката објављених у App Store-у. Оквир аутоматски управља ажурирањем интерфејса кроз механизам State и Data Flow — при промени података View се поново исцртава без ручног позива reloadData.
Главно
SwiftUI — декларативни UI оквир Apple-а, радикално другачији од UIKit-а. Уместо креирања контролера, прегледа и ручног управљања њиховим животним циклусом, програмер описује интерфејс у виду декларација: шта треба да буде на екрану, а не како то изградити. SwiftUI се заснива на принципу реактивности: интерфејс је функција стања. При промени стања (State), SwiftUI аутоматски прерачунава body свих зависних View-а и ажурира само измењене делове екрана. SwiftUI је доступан на iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ и visionOS 1+. Код SwiftUI-а је вишеплатформски: једна датотека ради на iPhone-у, iPad-у, Mac-у и Apple Watch-у уз минималне платформске адаптације. Према Apple WWDC Session 101 (2024), SwiftUI покрива преко 90% стандардних UI образаца App Store-а.
UIKit — императивни оквир (2008): програмер креира UIViewController, конфигурише subviews у viewDidLoad, имплементира delegate/datasource за UITableView и ажурира екран кроз reloadData или setNeedsLayout. SwiftUI замењује контролере једноставним структурама View, делегате — binding и onChange, Auto Layout — HStack/VStack/ZStack са модификаторима (padding, frame, offset). UIKit захтева ручно управљање меморијом кроз ARC; SwiftUI — структуре које не захтевају бројање референци. Перформансе SwiftUI-а су упоредиве са UIKit-ом: оквир користи diffing алгоритам за минимални скуп промена. У IT Sectr-у SwiftUI се користи за нове пројекте са iOS 17+ target-ом; пројекти са подршком за iOS 14–15 захтевају UIKit због ограничене компатибилности SwiftUI-а.
У SwiftUI-ју се интерфејс описује кроз ViewBuilder — result builder који трансформише скуп View-а у tuple или Group. Модификатори (.padding(), .font(), .foregroundColor()) креирају нове View-ове са измењеним поставкама, а не мутирају оригинални објекат. Сваки модификатор враћа нови View, што омогућава повезивање у ланац. ViewBuilder подржава if/else, switch, ForEach — условно и циклично рендеровање без посебних контролера. View у SwiftUI-ју је value type (struct), што гарантује предвидљиво понашање и елиминише race conditions.
View — протокол са једним захтевом: computed property body типа some View. Свака структура која одговара View описује свој део екрана у body. Тип some View — opaque return type који скрива конкретан тип враћеног View-а (спаривање VStack, HStack, ZStack, Text, Image итд.). Компајлер Swift изводи конкретан тип у фази компилације, чувајући перформансе директног позива без брисања типа.
import SwiftUI
struct GreetingView: View {
var name: String
var body: some View {
VStack(spacing: 12) {
Text("Здраво, \(name)!")
.font(.largeTitle)
.foregroundColor(.primary)
Text("Добро дошли у SwiftUI")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.ultraThinMaterial)
)
}
}Структура GreetingView прима параметар name и приказује два текстуална блока у вертикалном стек-у. Модификатори .font, .foregroundColor, .padding и .background конфигуришу изглед. SwiftUI позива body сваки пут када се промене улазни параметри (name) — поновно исцртавање се дешава само за измењене делове. У примеру се користи RoundedRectangle са .ultraThinMaterial — изворна blur позадина уграђена у SwiftUI.
@State — property wrapper који декларише локално стање које припада једном View-у. SwiftUI аутоматски управља меморијом State-а: при промени вредности body се поново исцртава, али само за View-ове који користе овај State. State је извор истине (source of truth) за једноставне типове (String, Int, Bool, enum). Не користите @State за сложене моделе података — за њих су намењени @StateObject и @ObservedObject. State треба да буде private и ускладиштен у самом View-у, а не да се преноси између компонената.
import SwiftUI
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 20) {
Text("Број: \(count)")
.font(.system(size: 48, weight: .bold))
Button(action: { count += 1 }) {
Label("Повећај", systemImage: "plus.circle")
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}Почетна вредност count = 0. Сваки притисак дугмета повећава count; SwiftUI аутоматски поново исцртава CounterView у потпуности (све View-ове). У UIKit-у би сличан сценарио захтевао IBOutlet, IBAction и ручно ажурирање label.text. @State гарантује да се View поново исцртава само при промени одређеног State-а — diffing алгоритам SwiftUI-а проналази минималне промене у стаблу.
@Binding — property wrapper који ствара двосмерну везу између View-а и података којима View не управља. Binding је референца на State (или други извор истине), која омогућава дете View-у да чита и мења вредност ускладиштену у родитељу. Binding се означава префиксом $: $count преноси Binding<Int> у дете View. Без Binding-а дете View не може да промени податке родитеља — може само да их чита.
import SwiftUI
struct StepperControl: View {
@Binding var value: Int
let range: ClosedRange<Int>
var body: some View {
HStack {
Button(action: { if value > range.lowerBound { value -= 1 } }) {
Image(systemName: "minus.circle")
}
Text("\(value)")
.frame(minWidth: 40)
Button(action: { if value < range.upperBound { value += 1 } }) {
Image(systemName: "plus.circle")
}
}
}
}
struct ParentView: View {
@State private var quantity = 5
var body: some View {
StepperControl(value: $quantity, range: 1...10)
}
}ParentView поседује State quantity и преноси Binding кроз $quantity. StepperControl може да мења value, а quantity у родитељу се аутоматски синхронизује. Binding није копија података, већ мост ка извору истине. Користите @Binding за прилагођене контроле, уређиваче и компоненте за вишекратну употребу које треба да мењају податке родитеља.
@StateObject — property wrapper за креирање и поседовање инстанце класе која одговара ObservableObject-у. View креира објекат једном у животном циклусу и поново се исцртава при промени његових @Published својстава. @ObservedObject — сличан wrapper, али View не поседује објекат — објекат се креира и чува изван View-а (преноси се кроз иницијализатор). Apple препоручује @StateObject за извор истине у хијерархији View-а и @ObservedObject за убризгавање зависности.
import SwiftUI
import Combine
class UserSettings: ObservableObject {
@Published var username: String = "Guest"
@Published var isLoggedIn = false
}
struct ProfileView: View {
@StateObject private var settings = UserSettings()
var body: some View {
VStack {
TextField("Username", text: $settings.username)
.textFieldStyle(.roundedBorder)
Toggle("Logged In", isOn: $settings.isLoggedIn)
if settings.isLoggedIn {
Text("Добро дошли, \(settings.username)!")
.font(.headline)
}
}
.padding()
}
}UserSettings — ObservableObject са два @Published својства. ProfileView поседује објекат кроз @StateObject. Промена username или isLoggedIn аутоматски поново исцртава ProfileView. @Published користи Combine Publisher за обавештавање SwiftUI-а о променама. За преношење settings дете View-овима користите @ObservedObject:
Apple дефинише четири нивоа Data Flow-а у SwiftUI-ју: @State (локални, value type), @Binding (двосмерни), @StateObject/@ObservedObject (reference type са ObservableObject-ом), @EnvironmentObject (глобални, убризгавање кроз окружење). EnvironmentObject омогућава пренос података кроз целу хијерархију View-а без експлицитног преношења у иницијализатору. Додатно, @AppStorage ради са UserDefaults-ом, @SceneStorage — са стањем сцене, @FetchRequest — са Core Data-ом. Избор нивоа Data Flow-а одређује архитектуру апликације: једноставни екрани користе State/Binding, модуларни — ObservedObject, обимни — EnvironmentObject + Redux-слична решења (TCA, Composable Architecture).
| Property Wrapper | Власништво | Тип | Када користити |
|---|---|---|---|
| @State | Локално | Value (struct, enum) | Једноставно стање једног View-а (бројач, toggle, текстуално поље) |
| @Binding | Спољно | Референца на State | Дете View које мења податке родитеља |
| @StateObject | Власништво View-а | Reference (class) | Извор истине за сложени модел података |
| @ObservedObject | Убризгавање | Reference (class) | Модел креиран ван View-а (пренет кроз init) |
| @EnvironmentObject | Глобално | Reference (class) | Подаци доступни целој хијерархији (ауторизација, тема) |
Често постављана питања
@State — за value types (struct, enum, String, Int) и локално стање једног View-а. SwiftUI аутоматски управља меморијом State-а. @StateObject — за reference types (class) који одговарају ObservableObject-у. @StateObject поседује објекат и поново исцртава View при промени @Published својстава. За једноставне бројаче користите @State; за моделе са логиком — @StateObject.
Да, SwiftUI се интегрише са UIKit-ом кроз UIHostingController (SwiftUI унутар UIKit-а) и UIViewRepresentable (UIKit унутар SwiftUI-а). UIHostingController облаже SwiftUI View у UIViewController. UIViewRepresentable омогућава коришћење UIKit компонената (MKMapView, WKWebView) у SwiftUI-ју. Ово је стандардни приступ за миграцију пројеката са UIKit-а на SwiftUI.
ViewBuilder — result builder (Swift 5.1) који трансформише скуп View-а у једну вредност типа TupleView, Group или ConditionalContent. ViewBuilder омогућава писање императивног if/else и switch-а унутар декларативног body-ја. Без ViewBuilder-а би било потребно враћати AnyView или Group за сваки условни блок. ViewBuilder је разлог зашто у body-ју није потребан зарез између View-ова.
Да, SwiftUI подржава iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ и visionOS 1+. Међутим, неки API-ји су доступни само на новијим верзијама: на пример, navigationStack (iOS 16+), Observable macro (iOS 17+). За уназад компатибилност користите #available и UIKit адаптације.
Xcode Debug View Hierarchy приказује стабло SwiftUI View-а са модификаторима и оквирима. Алат SwiftUI Inspector (десни панел Xcode-а) омогућава измену модификатора у реалном времену. self._printChanges() у body-ју логира узроке поновног исцртавања. Instruments са шаблоном SwiftUI прати перформансе View-а и открива прекомерна поновна исцртавања.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође