Specificități Swift în dezvoltarea mobilă: ce este, caracteristici cheie și cum funcționează

Autor: IT Sectr Publicat: 2026-06-25 Timp de citire: 17 min

Swift este limbajul de programare al Apple care combină puterea Objective-C cu siguranța limbajelor moderne. Spre deosebire de multe alte limbaje, Swift oferă construcții unice: tipuri de valoare cu copiere automată, Actori cu izolare la nivel de compilator, Property Wrappers pentru reutilizarea logicii proprietăților și Programare Orientată pe Protocoale ca alternativă la moștenirea clasică. Conform Documentației Apple Swift, aceste caracteristici fac codul mai sigur și mai performant.

Puncte Cheie

  • Struct — tip valoare, copiat la atribuire, nu suportă moștenirea. Class — tip referință, transmis prin referință, suportă moștenirea și deinit.
  • Actor — tip referință thread-safe cu izolare la nivel de compilator. Compilatorul interzice accesul concurent la starea mutabilă din diferite sarcini.
  • Property Wrappers — @Published, @State, @Binding încapsulează logica proprietăților în SwiftUI și Combine, eliminând codul boilerplate.
  • Generics permit scrierea de funcții și structuri type-safe fără legare la un tip specific. Programarea Orientată pe Protocoale folosește extension + protocol în locul ierarhiei de clase.
  • Enum cu valori asociate — un instrument puternic pentru modelarea stărilor. Fiecare caz poate stoca un set arbitrar de date de diferite tipuri.

Struct vs Class în Swift: tipuri de valoare și tipuri de referință

În Swift, struct este un tip de valoare, iar class este un tip de referință. Această diferență fundamentală determină comportamentul în timpul atribuirii, transmiterii către funcții și gestionării memoriei. Struct este copiat integral la fiecare atribuire, class este transmis prin referință — este copiat doar pointerul către obiectul din heap.

Semantica de valoare a Struct

Struct implementează automat semantica de valoare — fiecare instanță este independentă. Mutarea unei proprietăți struct este posibilă doar prin var, iar metodele care modifică proprietăți trebuie marcate ca mutating. Struct nu suportă moștenirea, dar se poate conforma protocoalelor. Biblioteca standard Swift folosește struct pentru String, Array, Dictionary, Int, Bool — toate tipurile fundamentale sunt tipuri de valoare.

swift
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"
// Copie completă — instanțe independente

Semantica de referință a Class

Class este stocată în heap și suportă egalitatea prin referință. Mai multe variabile pot referi același obiect, modificările printr-o referință sunt vizibile prin toate celelalte. Class suportă moștenirea, permite suprascrierea metodelor (override), are deinit pentru curățarea resurselor. În Swift, class este folosită mai rar decât struct — Apple recomandă să începeți cu struct și să treceți la class doar când sunt necesare moștenirea sau semantica de referință.

swift
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
// Aceeași referință — modificări vizibile peste tot

Alegerea între struct și class depinde de semantica datelor. Pentru configurări, modele de date și stări folosiți struct — copierea este mai sigură și mai previzibilă. Pentru obiecte cu identitate (sesiune utilizator, conexiune bază de date) și când este necesară moștenirea, folosiți class.

Actor — siguranța firelor în Swift

Actor este un tip de referință care își protejează starea mutabilă de accesul concurent. Compilatorul Swift garantează că variabilele actor pot fi accesate doar din același context actor — orice acces extern cauzează o eroare de compilare. Aceasta previne condițiile de cursă la nivel de limbaj, fără blocări manuale.

Izolarea Actor

Toate proprietățile și metodele actor sunt izolate implicit. Apelarea unei metode actor din exterior necesită await — Swift comută execuția către actor și înapoi. Actor sincronizează accesul secvențial: cererile de la diferite sarcini sunt puse în coadă. Aceasta garantează o stare consistentă în interiorul actorului. Metodele neizolate (nonisolated) pot fi apelate fără await, dar nu pot accesa proprietăți mutabile.

swift
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 "Cont Bancar"
    }
}

let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomic, fără condiție de cursă

Actor este util pentru manageri de stare, cache-uri și servicii de rețea unde mai multe sarcini citesc și scriu date concurent. Spre deosebire de sincronizarea manuală prin NSLock sau DispatchQueue, actor este verificat la compilare — este imposibil să greșești. Erorile de izolare apar la compilare, nu la runtime.

Property Wrappers: @Published, @State, @Binding

Property Wrapper este o adnotare care adaugă comportament unei proprietăți fără a-i modifica declarația. SwiftUI și Combine oferă wrapper-uri încorporate pentru gestionarea stării vizualizărilor. Compilatorul generează cod care încapsulează accesul la proprietate, adăugând logică de observare, sincronizare sau transformare.

@Published și @State

@Published este folosit în clase conforme cu ObservableObject pentru a publica automat modificările. Abonații Combine primesc notificări la fiecare actualizare. @State este starea locală a unei vizualizări SwiftUI. SwiftUI redesenează automat vizualizarea când @State se schimbă. @Binding creează o conexiune bidirecțională între o vizualizare părinte și copil fără a deține datele.

swift
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 = "Salut"
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        VStack {
            CounterDisplay(count: $viewModel.count)
            Text(greeting)
            Button("Incrementează", action: viewModel.increment)
        }
    }
}

struct CounterDisplay: View {
    @Binding var count: Int

    var body: some View {
        Text("Numărătoare: \(count)")
    }
}

Property Wrapper-urile personalizate sunt create folosind @propertyWrapper și o structură cu un câmp wrappedValue. Aceasta permite reutilizarea logicii: validare, normalizare, stocare UserDefaults. Property Wrapper-urile reduc semnificativ codul boilerplate și fac intenția dezvoltatorului explicită prin adnotare.

swift
@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 — valoare automat limitată

Generics și Programarea Orientată pe Protocoale

Generics este un mecanism puternic al Swift pentru scrierea de cod flexibil fără a pierde siguranța tipurilor. Funcțiile și tipurile generice funcționează cu orice tip care îndeplinește constrângerile. Programarea Orientată pe Protocoale (POP) este un paradigm Swift în care protocol + extension înlocuiesc moștenirea clasică a claselor, oferind compoziție de comportament.

Constrângeri Generice și Tipuri Asociate

Swift permite constrângerea parametrilor generici cu protocoale (clauze where). Protocol cu tip asociat este echivalentul generic pentru protocoale: tipul concret este determinat la momentul conformării. Aceasta este baza pentru colecții și algoritmi type-safe. Biblioteca standard Swift folosește activ generics: Array, Dictionary, Optional — toate sunt tipuri generice.

swift
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 — o metodă generică pentru toate tipurile Equatable

Extension de Protocol și Implementări Implicite

Extension-ul de protocol este un mecanism cheie al POP. Într-o extensie se poate furniza o implementare implicită a metodelor protocolului. Tipurile conforme cu protocolul obțin această implementare gratuit și o pot suprascrie dacă este necesar. Aceasta permite construirea de ierarhii de comportament fără moștenire de clase — o alternativă la moștenirea multiplă, care nu există în Swift.

swift
protocol Drivable {
    var speed: Double { get set }
    func drive()
}

extension Drivable {
    func drive() {
        if speed > 0 {
            print("Conduc la \(speed) km/h")
        }
    }
}

struct Bicycle: Drivable {
    var speed: Double = 15
}

struct Plane: Drivable {
    var speed: Double = 900

    func drive() {
        print("Zbor la \(speed) km/h")
    }
}

let bike = Bicycle()
bike.drive() // "Conduc la 15.0 km/h" — implicit

let plane = Plane()
plane.drive() // "Zbor la 900.0 km/h" — suprascris

POP cu extension permite compoziția prin multiple protocoale — un tip se poate conforma mai multor protocoale, obținând implementările lor. Aceasta este mai flexibilă decât moștenirea unică a claselor, unde întreaga ierarhie este fixă. Biblioteca standard Swift este construită pe POP: CustomStringConvertible, Equatable, Hashable, Codable — toate sunt protocoale cu extensii.

Enum cu valori asociate și Extension

Enum în Swift este o construcție semnificativ mai puternică decât în alte limbaje. Fiecare caz poate avea valori asociate — un set arbitrar de date de orice tip. Combinat cu extension și potrivirea de modele, enum devine baza pentru modelarea stărilor, rezultatelor operațiilor și mașinilor cu stări finite.

Valori Asociate și Potrivirea Modelelor

Valorile asociate permit fiecărui caz să stocheze date unice. De exemplu, cazul loading nu conține date, success conține rezultatul, failure conține o eroare. Potrivirea modelelor prin switch extrage valorile asociate și procesează fiecare caz. Compilatorul verifică exhaustivitatea (exhaustive switch) — aceasta elimină stările uitate.

swift
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("Se încarcă...")
    case .success(let data):
        print("Primit: \(data)")
    case .failure(let error):
        print("Eroare: \(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) durată \(duration)s")
}

Extension pentru Enum

Swift permite adăugarea de metode, proprietăți calculate și conformare la protocoale prin extension pentru enum. Acest lucru nu necesită modificarea declarației originale — codul rămâne curat și modular. Metodele din extension pot lucra cu valori asociate, calcula date derivate și implementa logică de afaceri.

swift
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 "Imagine \(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 cu valori asociate + extension este înlocuitorul claselor sealed din Kotlin sau al uniunilor discriminate din alte limbaje. Swift folosește această combinație pentru Result (un tip standard în biblioteca standard), Optional (Optional este un enum cu .none și .some) și gestionarea stărilor în SwiftUI. Potrivirea modelelor garantează că toate stările sunt procesate — erorile la runtime sunt imposibile.

Întrebări Frecvente

Cu ce diferă struct de class în Swift?

Struct — tip valoare, copiat la atribuire, nu suportă moștenirea. Class — tip referință, transmis prin referință, suportă moștenirea, deinit și verificarea identității (===). Apple recomandă să începeți cu struct și să treceți la class doar când este necesară semantica de referință.

Ce este Actor în Swift și când se utilizează?

Actor — tip referință thread-safe. Compilatorul interzice accesul concurent la starea mutabilă din contexte diferite. Folosiți Actor pentru manageri de stare, cache-uri și servicii accesate de mai multe sarcini. Apelarea metodelor actor necesită await.

Ce Property Wrapper-uri sunt utilizate în SwiftUI?

Principale: @State — stare locală a vizualizării; @Binding — conexiune la date fără posesie; @Published — publicarea modificărilor în ObservableObject; @StateObject — posesia ObservableObject; @EnvironmentObject — dependență din mediu. Wrapper-urile personalizate se creează prin @propertyWrapper.

Ce este Programarea Orientată pe Protocoale?

POP — un paradigm în care protocol + extension definesc comportamentul în locul moștenirii de clase. Un tip se conformează mai multor protocoale, obținând implementările lor gratuit. Aceasta este compoziție în loc de moștenire — mai flexibil și mai sigur. Biblioteca standard Swift (Equatable, Codable) este construită pe POP.

Cu ce diferă enum în Swift de enum în alte limbaje?

Enum în Swift suportă valori asociate — fiecare caz poate stoca date arbitrare de diferite tipuri. Combinat cu potrivirea modelelor (switch), oferă un model puternic pentru stări, erori și Design-Dominat de Domeniu. Optional și Result sunt enum-uri standard Swift cu valori asociate.

Rezumat

  • Struct vs Class — diferență fundamentală: tipurile de valoare sunt copiate, tipurile de referință sunt transmise prin referință. Struct nu suportă moștenirea, class da. Apple recomandă implicit struct.
  • Actor — siguranța firelor la nivel de compilator. Stare mutabilă izolată, acces prin await, protecție împotriva condițiilor de cursă fără blocări manuale.
  • Property Wrappers — @Published, @State, @Binding și personalizate prin @propertyWrapper. Reduc codul boilerplate și fac intenția explicită prin adnotare.
  • Generics — funcții și tipuri type-safe cu constrângeri where. Protocol + tip asociat pentru abstracții. Biblioteca standard Swift este construită în întregime pe generics.
  • Programarea Orientată pe Protocoale — compoziție de comportament prin extension de protocol. Implementările implicite permit reutilizarea codului fără moștenirea claselor.
  • Enum cu valori asociate — un model puternic pentru stări. Fiecare caz stochează date unice. Potrivirea modelelor garantează că toate stările sunt procesate.
  • Extension — adaugă metode, proprietăți calculate și conformare la protocoale pentru orice tip, inclusiv enum. Codul rămâne modular și curat fără a modifica declarația originală.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul