Swift je programovací jazyk společnosti Apple, který kombinuje sílu Objective-C s bezpečností moderních jazyků. Na rozdíl od mnoha jiných jazyků Swift nabízí jedinečné konstrukce: hodnotové typy s automatickým kopírováním, Actors s izolací na úrovni kompilátoru, Property Wrappers pro opětovné použití logiky vlastností a Protokolově Orientované Programování jako alternativu ke klasickému dědění. Podle Apple Swift dokumentace tyto funkce činí kód bezpečnějším a výkonnějším.
Klíčové Body
Ve Swift je struct hodnotový typ, zatímco class je referenční typ. Tento zásadní rozdíl určuje chování při přiřazení, předávání funkcím a správě paměti. Struct je při každém přiřazení zcela zkopírován, class je předáván odkazem — kopíruje se pouze ukazatel na objekt v haldě.
Struct automaticky implementuje hodnotovou sémantiku — každá instance je nezávislá. Změna vlastnosti struct je možná pouze přes var a metody, které mění vlastnosti, musí být označeny jako mutating. Struct nepodporuje dědění, ale může vyhovovat protokolům. Standardní knihovna Swift používá struct pro String, Array, Dictionary, Int, Bool — všechny základní typy jsou hodnotové typy.
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"
// Úplná kopie — nezávislé instance
Class je uložena v haldě a podporuje referenční rovnost. Několik proměnných může odkazovat na stejný objekt, změny přes jeden odkaz jsou viditelné přes všechny ostatní. Class podporuje dědění, umožňuje přepisování metod (override), má deinit pro čištění zdrojů. Ve Swift se class používá méně často než struct — Apple doporučuje začínat struct a přejít na class pouze tehdy, když je potřeba dědění nebo referenční sémantika.
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
// Stejný odkaz — změny viditelné všude
Volba mezi struct a class závisí na sémantice dat. Pro konfigurace, datové modely a stavy používejte struct — kopírování je bezpečnější a předvídatelnější. Pro objekty s identitou (uživatelská relace, připojení k databázi) a když je potřeba dědění, používejte class.
Actor je referenční typ, který chrání svůj měnitelný stav před současným přístupem. Kompilátor Swift zaručuje, že proměnné actor jsou přístupné pouze ze stejného kontextu actor — jakýkoli vnější přístup způsobí chybu kompilace. To zabraňuje datovým závodům na úrovni jazyka, bez ručních zámků.
Všechny vlastnosti a metody actor jsou ve výchozím nastavení izolovány. Volání metody actor z vnějšku vyžaduje await — Swift přepne provádění do actor a zpět. Actor synchronizuje přístup sekvenčně: požadavky z různých úkolů jsou zařazeny do fronty. To zaručuje konzistentní stav uvnitř actor. Neizolované metody (nonisolated) lze volat bez await, ale nemají přístup k měnitelným vlastnostem.
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 "Bankovní účet"
}
}
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomicky, bez závodní podmínky
Actor je užitečný pro správce stavu, mezipaměti a síťové služby, kde několik úkolů současně čte a zapisuje data. Na rozdíl od ruční synchronizace přes NSLock nebo DispatchQueue je actor kontrolován při kompilaci — chyba je nemožná. Chyby izolace se objevují při kompilaci, ne za běhu.
Property Wrapper je anotace, která přidává chování vlastnosti bez změny její deklarace. SwiftUI a Combine poskytují vestavěné wrappery pro správu stavu zobrazení. Kompilátor generuje kód, který obaluje přístup k vlastnosti a přidává logiku pozorování, synchronizace nebo transformace.
@Published se používá ve třídách vyhovujících ObservableObject k automatickému publikování změn. Předplatitelé Combine dostávají oznámení při každé aktualizaci. @State je místní stav zobrazení SwiftUI. SwiftUI automaticky překreslí zobrazení, když se @State změní. @Binding vytváří obousměrné spojení mezi rodičovským a podřízeným zobrazením bez vlastnictví dat.
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 = "Ahoj"
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
CounterDisplay(count: $viewModel.count)
Text(greeting)
Button("Zvýšit", action: viewModel.increment)
}
}
}
struct CounterDisplay: View {
@Binding var count: Int
var body: some View {
Text("Počet: \(count)")
}
}
Vlastní Property Wrappers se vytvářejí pomocí @propertyWrapper a struktury s polem wrappedValue. To umožňuje opětovné použití logiky: validace, normalizace, ukládání do UserDefaults. Property Wrappers výrazně snižují boilerplate kód a činí záměr vývojáře explicitním prostřednictvím anotace.
@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 — hodnota automaticky omezena
Generics je mocný mechanismus Swift pro psaní flexibilního kódu bez ztráty typové bezpečnosti. Generické funkce a typy pracují s jakýmkoli typem, který splňuje omezení. Protokolově Orientované Programování (POP) je paradigma Swift, kde protocol + extension nahrazují klasické dědění tříd a poskytují kompozici chování.
Swift umožňuje omezovat generické parametry protokoly (klauzule where). Protokol s přidruženým typem je generický ekvivalent pro protokoly: konkrétní typ je určen v okamžiku vyhovění. To je základ pro typově bezpečné kolekce a algoritmy. Standardní knihovna Swift aktivně používá generics: Array, Dictionary, Optional — všechny jsou generické typy.
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 — jedna generická metoda pro všechny typy Equatable
Rozšíření protokolu je klíčový mechanismus POP. V rozšíření lze poskytnout výchozí implementaci metod protokolu. Typy vyhovující protokolu získají tuto implementaci zdarma a v případě potřeby ji mohou přepsat. To umožňuje vytvářet hierarchie chování bez dědění tříd — alternativa k vícenásobnému dědění, které ve Swift neexistuje.
protocol Drivable {
var speed: Double { get set }
func drive()
}
extension Drivable {
func drive() {
if speed > 0 {
print("Jízda rychlostí \(speed) km/h")
}
}
}
struct Bicycle: Drivable {
var speed: Double = 15
}
struct Plane: Drivable {
var speed: Double = 900
func drive() {
print("Let rychlostí \(speed) km/h")
}
}
let bike = Bicycle()
bike.drive() // "Jízda rychlostí 15.0 km/h" — výchozí
let plane = Plane()
plane.drive() // "Let rychlostí 900.0 km/h" — přepsáno
POP s rozšířením umožňuje kompozici prostřednictvím více protokolů — typ může vyhovovat několika protokolům a získat jejich implementace. To je flexibilnější než jediné dědění tříd, kde je celá hierarchie pevná. Standardní knihovna Swift je postavena na POP: CustomStringConvertible, Equatable, Hashable, Codable — vše jsou protokoly s rozšířeními.
Enum ve Swift je výrazně mocnější konstrukcí než v jiných jazycích. Každý případ může mít přidružené hodnoty — libovolnou sadu dat jakéhokoli typu. V kombinaci s rozšířením a porovnáváním vzorů se enum stává základem pro modelování stavů, výsledků operací a konečných automatů.
Přidružené hodnoty umožňují každému případu ukládat jedinečná data. Například případ loading neobsahuje data, success obsahuje výsledek, failure obsahuje chybu. Porovnávání vzorů přes switch extrahuje přidružené hodnoty a zpracovává každý případ. Kompilátor kontroluje úplnost (exhaustive switch) — to eliminuje zapomenuté stavy.
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("Načítání...")
case .success(let data):
print("Přijato: \(data)")
case .failure(let error):
print("Chyba: \(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) doba trvání \(duration)s")
}
Swift umožňuje přidávat metody, vypočítávané vlastnosti a vyhovění protokolům prostřednictvím extension pro enum. To nevyžaduje změnu původní deklarace — kód zůstává čistý a modulární. Metody v extension mohou pracovat s přidruženými hodnotami, počítat odvozená data a implementovat obchodní 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 "Obrázek \(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 s přidruženými hodnotami + extension je náhradou za sealed třídy z Kotlinu nebo diskriminované svazy z jiných jazyků. Swift používá tuto kombinaci pro Result (standardní typ ve standardní knihovně), Optional (Optional je enum s .none a .some) a zpracování stavů ve SwiftUI. Porovnávání vzorů zaručuje, že všechny stavy jsou zpracovány — chyby za běhu jsou nemožné.
Často Kladené Otázky
Struct — hodnotový typ, kopíruje se při přiřazení, nepodporuje dědění. Class — referenční typ, předává se odkazem, podporuje dědění, deinit a kontrolu identity (===). Apple doporučuje začínat struct a přejít na class pouze při potřebě referenční sémantiky.
Actor — vláknově bezpečný referenční typ. Kompilátor zakazuje současný přístup k měnitelnému stavu z různých kontextů. Použijte Actor pro správce stavu, mezipaměti a služby přístupné více úkoly. Volání metod actor vyžaduje await.
Hlavní: @State — místní stav zobrazení; @Binding — připojení dat bez vlastnictví; @Published — publikování změn v ObservableObject; @StateObject — vlastnictví ObservableObject; @EnvironmentObject — závislost z prostředí. Vlastní wrappery se vytvářejí pomocí @propertyWrapper.
POP — paradigma, kde protocol + extension definují chování místo dědění tříd. Typ vyhovuje několika protokolům a získává jejich implementace zdarma. To je kompozice místo dědění — flexibilnější a bezpečnější. Standardní knihovna Swift (Equatable, Codable) je postavena na POP.
Enum ve Swift podporuje přidružené hodnoty — každý případ může ukládat libovolná data různých typů. V kombinaci s porovnáváním vzorů (switch) poskytuje mocný model pro stavy, chyby a doménově řízený design. Optional a Result jsou standardní enumy Swift s přidruženými hodnotami.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.