Swift je Apple-ov programski jezik koji kombinuje snagu Objective-C-a sa sigurnošću modernih jezika. Za razliku od mnogih drugih jezika, Swift nudi jedinstvene konstrukcije: value types sa automatskim kopiranjem, Actors sa izolacijom na nivou kompajlera, Property Wrappers za ponovno korišćenje logike svojstava i Protocol Oriented Programming kao alternativu klasičnom nasleđivanju. Prema Apple Swift dokumentaciji, ove mogućnosti čine kod sigurnijim i efikasnijim.
Glavno
U Swift-u, struct je value type, a class je reference type. Ova fundamentalna razlika određuje ponašanje prilikom dodele, prosleđivanja funkcijama i upravljanja memorijom. Struct se kopira u celosti pri svakoj dodeli, class se prenosi po referenci — kopira se samo pokazivač na objekat u heap-u.
Struct automatski implementira value semantics — svaka instanca je nezavisna. Mutacija svojstva struct je moguća samo kroz var, a metode koje menjaju svojstva moraju biti označene kao mutating. Struct ne podržava nasleđivanje, ali može da conformira protokolima. Swift standardna biblioteka koristi struct za String, Array, Dictionary, Int, Bool — svi fundamentalni tipovi su value types.
struct User {
let id: Int
var name: String
mutating func updateName(_ newName: String) {
name = newName
}
}
var user1 = User(id: 1, name: "Alice")
var user2 = user1
user2.updateName("Bob")
// user1.name === "Alice", user2.name === "Bob"
// Potpuna kopija — nezavisne instance
Class se čuva u heap-u i podržava referentnu jednakost. Više varijabli može referencirati isti objekat, promene kroz jednu referencu su vidljive kroz sve ostale. Class podržava nasleđivanje, omogućava override metoda (override), ima deinit za čišćenje resursa. U Swift-u, class se koristi ređe od struct-a — Apple preporučuje početak sa struct-om i prelazak na class samo kada su potrebni nasleđivanje ili referentna semantika.
class Car {
let model: String
var speed: Int
init(model: String, speed: Int) {
self.model = model
self.speed = speed
}
func accelerate(_ amount: Int) {
speed += amount
}
}
let car1 = Car(model: "Tesla", speed: 0)
let car2 = car1
car2.accelerate(50)
// car1.speed === 50, car2.speed === 50
// Ista referenca — promene vidljive svuda
Izbor između struct i class zavisi od semantike podataka. Za konfiguracije, modele podataka i stanja koristite struct — kopiranje je sigurnije i predvidljivije. Za objekte sa identitetom (user session, database connection) i kada je potrebno nasleđivanje, koristite class.
Actor je reference type koji štiti svoje mutable stanje od istovremenog pristupa. Swift kompajler garantuje da se varijablama actor može pristupiti samo iz istog actor konteksta — pokušaj pristupa spolja izaziva grešku kompajliranja. Ovo sprečava data races na nivou jezika, bez ručnih blokada.
Sva svojstva i metode actor su podrazumevano izolovani. Pozivanje metode actor spolja zahteva await — Swift prebacuje izvršenje u actor i nazad. Actor sinhronizuje pristup sekvencijalno: zahtevi iz različitih taskova se poređaju u red. Ovo garantuje konzistentno stanje unutar actor-a. Neizolovane metode (nonisolated) mogu se pozivati bez await, ali nemaju pristup mutable svojstvima.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
nonisolated func accountInfo() -> String {
return "Bankovni račun"
}
}
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomski, bez race condition
Actor je koristan za menadžere stanja, keševe i mrežne servise gde više taskova istovremeno čita i piše podatke. Za razliku od ručne sinhronizacije kroz NSLock ili DispatchQueue, actor se proverava na nivou kompajlera — greška je nemoguća. Greške izolacije se pojavljuju u fazi kompajliranja, ne u runtime-u.
Property Wrapper je anotacija koja dodaje ponašanje svojstvu bez promene njegove deklaracije. SwiftUI i Combine pružaju ugrađene wrapper-e za upravljanje stanjem prikaza. Kompajler generiše kod koji obavija pristup svojstvu, dodajući logiku posmatranja, sinhronizacije ili transformacije.
@Published se koristi u klasama koje conformiraju ObservableObject za automatsko objavljivanje promena. Combine pretplatnici dobijaju obaveštenja pri svakom ažuriranju. @State je lokalno stanje SwiftUI prikaza. SwiftUI automatski ponovo crta prikaz kada se @State promeni. @Binding stvara dvosmernu vezu između roditeljskog i dete prikaza bez vlasništva nad podacima.
import SwiftUI
import Combine
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct ContentView: View {
@State private var greeting: String = "Zdravo"
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
CounterDisplay(count: $viewModel.count)
Text(greeting)
Button("Povećaj", action: viewModel.increment)
}
}
}
struct CounterDisplay: View {
@Binding var count: Int
var body: some View {
Text("Brojač: \(count)")
}
}
Custom Property Wrapper se kreira kroz @propertyWrapper i strukturu sa poljem wrappedValue. Ovo omogućava ponovno korišćenje logike: validaciju, normalizaciju, UserDefaults skladištenje. Property Wrappers značajno smanjuju boilerplate kod i čine nameru programera eksplicitnom kroz anotaciju.
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
let range: ClosedRange<T>
init(wrappedValue: T, range: ClosedRange<T>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
struct Settings {
@Clamped(range: 0...100) var volume: Int = 50
}
var s = Settings()
s.volume = 150
// s.volume === 100 — vrednost automatski ograničena
Generics je moćan mehanizam Swift-a za pisanje fleksibilnog koda bez gubitka tipizacije. Generičke funkcije i tipovi rade sa bilo kojim tipom koji zadovoljava ograničenja. Protocol Oriented Programming (POP) je Swift paradigma gde protocol + extension zamenjuju klasično nasleđivanje klasa, obezbeđujući kompoziciju ponašanja.
Swift dozvoljava ograničavanje generičkih parametara protokolima (where klauzule). Protocol sa associated type je generički ekvivalent za protokole: konkretan tip se određuje u trenutku conforminga. Ovo je osnova za type-safe kolekcije i algoritme. Swift standardna biblioteka aktivno koristi generics: Array, Dictionary, Optional — sve su generički tipovi.
protocol Cacheable {
associatedtype Key: Hashable
associatedtype Value
func get(_ key: Key) -> Value?
mutating func set(_ value: Value, for key: Key)
}
struct MemoryCache<K: Hashable, V>: Cacheable {
private var storage: [K: V] = [:]
typealias Key = K
typealias Value = V
func get(_ key: K) -> V? {
return storage[key]
}
mutating func set(_ value: V, for key: K) {
storage[key] = value
}
}
func firstMatch<T: Equatable>(in array: [T], target: T) -> Int? {
for (index, item) in array.enumerated() {
if item == target {
return index
}
}
return nil
}
let numbers = [10, 20, 30, 40]
let index = firstMatch(in: numbers, target: 30)
// index === 2 — jedan generički metod za sve Equatable tipove
Protocol extension je ključni mehanizam POP-a. U extension-u se može dati podrazumevana implementacija metoda protokola. Tip koji conformira protokolu dobija ovu implementaciju besplatno i može je override-ovati po potrebi. Ovo omogućava izgradnju hijerarhije ponašanja bez nasleđivanja klasa — alternativa višestrukom nasleđivanju, koje ne postoji u Swift-u.
protocol Drivable {
var speed: Double { get set }
func drive()
}
extension Drivable {
func drive() {
if speed > 0 {
print("Vožnja brzinom \(speed) km/h")
}
}
}
struct Bicycle: Drivable {
var speed: Double = 15
}
struct Plane: Drivable {
var speed: Double = 900
func drive() {
print("Letenje brzinom \(speed) km/h")
}
}
let bike = Bicycle()
bike.drive() // "Vožnja brzinom 15.0 km/h" — podrazumevano
let plane = Plane()
plane.drive() // "Letenje brzinom 900.0 km/h" — override
POP sa extension-om daje kompoziciju kroz višestruke protokole — tip može conformirati više protokola, dobijajući njihove implementacije. Ovo je fleksibilnije od jedinstvenog nasleđivanja klasa gde je cela hijerarhija fiksna. Swift standardna biblioteka je izgrađena na POP-u: CustomStringConvertible, Equatable, Hashable, Codable — sve su to protokoli sa extension-ima.
Enum u Swift-u je značajno moćnija konstrukcija nego u drugim jezicima. Svaki case može imati associated values — proizvoljan skup podataka bilo kog tipa. U kombinaciji sa extension-om i pattern matching-om, enum postaje osnova za modeliranje stanja, rezultata operacija i konačnih automata.
Associated values omogućavaju svakom case-u da čuva jedinstvene podatke. Na primer, case loading ne sadrži podatke, success sadrži rezultat, failure sadrži grešku. Pattern matching kroz switch izvlači associated values i obrađuje svaki case. Kompajler proverava potpunost pokrivenosti (exhaustive switch) — ovo eliminiše zaboravljena stanja.
enum NetworkResult<T> {
case loading
case success(T)
case failure(Error)
}
enum MediaFile {
case image(url: URL, width: Int, height: Int)
case video(url: URL, duration: Double)
case audio(url: URL, bitrate: Int)
}
func handle(_ result: NetworkResult<String>) {
switch result {
case .loading:
print("Učitavanje...")
case .success(let data):
print("Primljeno: \(data)")
case .failure(let error):
print("Greška: \(error.localizedDescription)")
}
}
let file = MediaFile.video(url: URL(string: "https://example.com/video.mp4")!, duration: 120)
if case .video(let url, let duration) = file {
print("Video \(url) trajanje \(duration)s")
}
Swift dozvoljava dodavanje metoda, computed properties i conforminga protokolima kroz extension za enum. Ovo ne zahteva promenu originalne deklaracije — kod ostaje čist i modularen. Metode u extension-u mogu raditi sa associated values, izračunavati izvedene podatke i implementirati poslovnu logiku.
extension MediaFile {
var fileName: String {
switch self {
case .image(let url, _, _),
.video(let url, _),
.audio(let url, _):
return url.lastPathComponent
}
}
var description: String {
switch self {
case .image(_, let w, let h):
return "Slika \(w)x\(h)"
case .video(_, let d):
return "Video \(d)s"
case .audio(_, let b):
return "Audio \(b) kbps"
}
}
}
extension MediaFile: Equatable {
static func == (lhs: MediaFile, rhs: MediaFile) -> Bool {
return lhs.fileName == rhs.fileName
}
}
let files: [MediaFile] = [file]
files.forEach { print($0.description) }
// "Video 120.0s"
Enum sa associated values + extension je zamena za sealed classes iz Kotlin-a ili discriminated unions iz drugih jezika. Swift koristi ovu kombinaciju za Result (standardni tip u standardnoj biblioteci), Optional (Optional je enum sa .none i .some) i obradu stanja u SwiftUI-ju. Pattern matching garantuje da su sva stanja obrađena — greške u runtime-u su nemoguće.
Često postavljana pitanja
Struct — value type, kopira se pri dodeli, ne podržava nasleđivanje. Class — reference type, prenosi se po referenci, podržava nasleđivanje, deinit i proveru identiteta (===). Apple preporučuje početak sa struct-om i prelazak na class samo kada je potrebna referentna semantika.
Actor — thread-safe reference type. Kompajler zabranjuje istovremeni pristup mutable stanju iz različitih konteksta. Koristite Actor za menadžere stanja, keševe i servise kojima pristupa više taskova. Pozivanje metoda actor zahteva await.
Glavni: @State — lokalno stanje prikaza; @Binding — veza sa podacima bez vlasništva; @Published — objavljivanje promena u ObservableObject; @StateObject — vlasništvo ObservableObject; @EnvironmentObject — zavisnost iz okruženja. Custom wrapper-i se kreiraju kroz @propertyWrapper.
POP — paradigma gde protocol + extension definišu ponašanje umesto class inheritance. Tip conformira više protokola, dobijajući njihove implementacije besplatno. Ovo je kompozicija umesto nasleđivanja — fleksibilnije i sigurnije. Swift standardna biblioteka (Equatable, Codable) je izgrađena na POP-u.
Enum u Swift-u podržava associated values — svaki case može čuvati proizvoljne podatke različitih tipova. U kombinaciji sa pattern matching-om (switch), ovo daje moćan model za stanja, greške i Domain-Driven Design. Optional i Result su standardni Swift enum-ovi sa associated values.
Sumirani
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.