Unowned Reference: co to jest, składnia i zastosowanie w aplikacjach mobilnych

Autor: IT Sectr Opublikowano: 2026-03-30 Czas czytania: 9 min

Unowned Reference (referencja nieposiadająca) — to nieposiadająca referencja w Swift, która nie zwiększa retain count obiektu i, w przeciwieństwie do weak, nie ustawia się na nil po jego zwolnieniu. Według Apple Swift Language Guide, 2026, unowned stosuje się, gdy mamy gwarancję, że obiekt żyje co najmniej tak długo, jak obiekt, który się do niego odwołuje. W przeciwieństwie do Weak Reference, unowned nie wymaga unwrap — to typ non-optional, co czyni kod czystszym, ale nakłada na programistę odpowiedzialność za gwarancję czasu życia.

Najważniejsze

  • Unowned Reference — nieposiadająca referencja bez automatycznego zerowania; non-optional, nie zwiększa retain count
  • Gwarancja — stosowana, gdy obiekt gwarantowanie nie może zostać zwolniony przed obiektem odwołującym się
  • Różnica od weak — unowned nie jest zerowany do nil (ryzyko crash), weak jest zerowany (bezpiecznie)
  • Scenariusze — parent-child z gwarancją życia, domknięcia z unowned self, singletony i Service Locator
  • Ryzyko — odwołanie do zwolnionego unowned obiektu powoduje runtime crash (EXC_BAD_ACCESS)

Co to jest Unowned Reference?

Unowned Reference — to nieposiadająca referencja do obiektu w ARC, która nie zwiększa jego retain count. W przeciwieństwie do weak, unowned nie jest zerowana po deallocacji obiektu: nadal wskazuje na obszar pamięci, który został już zwolniony. Odwołanie do takiej referencji powoduje runtime crash z EXC_BAD_ACCESS.

Termin „nieposiadająca” odzwierciedla semantykę: obiekt istnieje, ale nikt nie odpowiada za jego czas życia. Programista jawnie deklaruje: „gwarantuję, że ten obiekt będzie żył, dopóki się do niego odwołuję”. Kompilator nie sprawdza tej gwarancji — to kontrakt na poziomie programisty.

Według Swift.org Documentation, 2026, unowned referencje są preferowane nad weak w scenariuszach z gwarantowanym czasem życia, ponieważ: nie wymagają typu opcjonalnego (czystszy kod), nie wymagają unwrap (mniej force-unwrap lub guard let) i nie mają narzutów na prowadzenie zeroing weak-tablicy. Jednak każde naruszenie kontraktu — crash.

Składnia unowned w Swift

W Swift unowned referencje deklaruje się słowem kluczowym unowned przed let lub var. W przeciwieństwie do weak, unowned może być zarówno let, jak i var i nie wymaga typu opcjonalnego. Ta właściwość czyni unowned wygodnym dla referencji, które nie mogą być nil zgodnie z logiką dziedziny.

swift
class Country {
    let name: String
    var capital: City!           // zostanie ustawione po inicjalizacji
    init(name: String) { self.name = name }
}

class City {
    let name: String
    unowned let country: Country   // ✅ unowned let — gwarancja życia

    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// Użycie
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — brak retain cycle

W tym przykładzie City unowned let country — miasto nie może istnieć bez kraju. Jeśli kraj zniknie, miasto (i referencja) stracą sens. Semantycznie to idealny przypadek dla unowned: gwarancja czasu życia istnieje, optional nie jest potrzebny, retain cycle nie powstaje.

unowned var

unowned var jest dozwolone, ale występuje rzadziej. Używane, gdy referencja może zostać zastąpiona (np. przepięcie dziecka do innego rodzica). Przy zamianie zwolnienie starego obiektu — odpowiedzialność zewnętrznego właściciela.

Unowned Optional

W Swift 5.0+ pojawiło się wsparcie dla unowned optional (unowned let x: Type?). To kompromis: unowned gwarantuje, że jeśli referencja nie jest nil, to obiekt żyje. Zachowanie przy zwolnieniu — crash, jak w przypadku zwykłego unowned.

Unowned vs Weak: kiedy używać czego

Wybór między unowned a weak — jedna z częstych decyzji przy projektowaniu architektury Swift. Rozważmy kryteria i zalecenia dla każdego przypadku.

KryteriumWeakUnowned
OptionalTak (Type?)Nie (Type)
Zerowanie przy deallocacjiAuto na nilNie (ryzyko wiszącego wskaźnika)
Typ (let/var)Tylko varlet lub var
WydajnośćNarzuty na weak-tablicęMinimalne (zwykły wskaźnik)
BezpieczeństwoBezpiecznie (nil sprawdzany)Ryzyko EXC_BAD_ACCESS
Gwarancja czasu życiaNie wymaganaWymagana jawna gwarancja

Praktyczna zasada

Używaj weak, jeśli istnieje choćby najmniejsza wątpliwość co do czasu życia obiektu. Weak jest bezpieczne, zrozumiałe i nie wymaga dowodów. Używaj unowned tylko wtedy, gdy wykluczysz wszystkie scenariusze, w których obiekt może zostać zwolniony wcześniej. Typowe przypadki: dziecko nieistniejące bez rodzica; domknięcie wykonujące się synchronicznie; odwołanie do obiektu w obrębie jego inicjalizatora.

Według Airbnb Swift Style Guide, 2025, w dużych bazach kodu zaleca się używanie weak domyślnie, a unowned — tylko z jawnym komentarzem wyjaśniającym gwarancję czasu życia. Zmniejsza to ryzyko nieoczywistych crashy przy refaktoryzacji.

Unowned self w domknięciach

Domknięcia (closures) — drugi co do częstości scenariusz użycia unowned po relacjach parent-child. Capture list [unowned self] stosuje się, gdy self gwarantowanie żyje dłużej niż domknięcie. Rozważmy prawidłowe i nieprawidłowe scenariusze.

Kiedy unowned self jest bezpieczne

Synchroniczne domknięcia — sorted, filter, map. Wykonują się natychmiast w bieżącym wątku, self na pewno żyje. Capture list z unowned jest tu dopuszczalny i daje czystszy kod.

swift
class DataProcessor {
    var items: [Int] = [3, 1, 4, 1, 5]

    func processSorted() {
        // ✅ unowned self — sorted wykonuje się synchronicznie, self gwarantowanie żyje
        let sorted = items.sorted { [unowned self] a, b in
            return self.customCompare(a, b)
        }
    }

    func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}

Kiedy unowned self jest niebezpieczne

Asynchroniczne domknięcia — z opóźnieniem, żądaniami sieciowymi, animacjami. Self może zostać zwolnione między umieszczeniem domknięcia a jego wykonaniem. Tu unowned self → crash. Używaj [weak self].

swift
class NetworkLoader {
    func loadData() {
        // ❌ NIEBEZPIECZNE: unowned self w asynchronicznym domknięciu
        URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
            self.handleResponse(data)  // CRASH jeśli self został zwolniony
        }.resume()
    }

    func handleResponse(_ data: Data?) { }

    // ✅ PRAWIDŁOWO: weak self + guard
    func loadDataSafe() {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
            guard let self else { return }
            self.handleResponse(data)
        }.resume()
    }
}

Zapamiętaj zasadę: unowned self — tylko dla synchronicznych domknięć wykonujących się natychmiast. Dla asynchronicznych — zawsze weak self + guard let. Wyjątek: jeśli jawnie przechowujesz referencję do obiektu do momentu zakończenia domknięcia (np. przez zachowanie silnego przechwycenia w innej zmiennej).

Ryzyka unowned i jak ich unikać

Unowned — potężne, ale niebezpieczne narzędzie. Rozważmy rzeczywiste scenariusze, w których unowned może prowadzić do crasha, oraz metody minimalizacji ryzyka.

Refaktoryzacja i zmiana gwarancji

Główne ryzyko unowned — zmiana logiki biznesowej, w wyniku której gwarancja czasu życia przestaje być spełniona. Programista refaktoryzuje kod: zmienia własność, wprowadza opóźnione zwalnianie, dodaje buforowanie — i unowned referencja zamienia się w bombę z opóźnionym zapłonem. Kompilator nie ostrzeże — tylko crash na urządzeniu użytkownika.

Zalecenie: używaj unowned tylko wtedy, gdy gwarancja czasu życia jest oczywista i udokumentowana. Dodawaj komentarz do każdego unowned: dlaczego ta referencja jest bezpieczna i w jakich warunkach może zostać naruszona.

Unowned w hierarchiach UIKit

UIKit — strefa podwyższonego ryzyka dla unowned. ViewController może zostać zwolniony w dowolnym momencie przy nawigacji (pop, dismiss), wyładowaniu z pamięci, zmianie orientacji. Jeśli przekazujesz ViewController do domknięcia z unowned self — przy powrocie z tła lub zakończeniu animacji self może być nil.

Najlepsze praktyki

Aby zmniejszyć ryzyko przy używaniu unowned, przestrzegaj tych zasad:

  • Preferuj weak domyślnie — weak jest bezpieczne, unowned — optymalizacja, a nie standard
  • Dokumentuj gwarancje — dla każdego unowned pisz komentarz z uzasadnieniem
  • Unikaj unowned w ViewController — cykl życia UIKit jest nieprzewidywalny dla unowned gwarancji
  • Używaj unowned tylko dla synchronicznych domknięć — sorted, filter, map — bezpieczni kandydaci
  • Sprawdzaj przy code review — każde unowned wymaga uzasadnienia od autora kodu
  • Migruj na weak przy najmniejszych wątpliwościach — strata w czytelności (jeden guard let) jest mniejsza niż crash w produkcji
swift
// Przykład: udokumentowana unowned referencja z jawnym uzasadnieniem
class InvoiceLineItem {
    let productName: String
    let price: Decimal

    // unowned Invoice — InvoiceLineItem nie może istnieć bez Invoice.
    // Invoice tworzy Item i usuwa go przy swoim usunięciu.
    // Gwarancja: Invoice żyje co najmniej tak długo, jak Item.
    unowned let invoice: Invoice

    init(productName: String, price: Decimal, invoice: Invoice) {
        self.productName = productName
        self.price = price
        self.invoice = invoice
    }
}

// To silna gwarancja: Invoice usuwa wszystkie Item w deinit.
// naruszenie gwarancji = błąd w logice biznesowej, który trzeba naprawić.

Dokumentowanie gwarancji — profesjonalny standard. W dużych projektach (Airbnb, Uber) code review wymaga uzasadnienia każdego unowned. Jeśli gwarancja nie jest oczywista — używaj weak. Komentarz do unowned pomaga przyszłym programistom zrozumieć, dlaczego tu nie ma weak i jakie warunki mogą złamać gwarancję.

Często zadawane pytania

Co się stanie przy odwołaniu do unowned referencji po zwolnieniu obiektu?

Runtime crash z EXC_BAD_ACCESS. Swift nie sprawdza poprawności unowned referencji przy dostępie — to po prostu „surowy” wskaźnik. Jeśli obiekt został zwolniony, pamięć jest nadpisana, a odwołanie do niej kończy się awarią. To niełapalny wyjątek (nie try-catch).

Czy można używać unowned z protokołami?

Tak, jeśli protokół dziedziczy po AnyObject. Unowned działa ze wszystkimi typami referencyjnymi: klasy, protokoły AnyObject, obiekty Objective-C. Typy wartościowe (struct, enum) nie obsługują unowned, ponieważ nie uczestniczą w ARC.

Kiedy unowned jest bezpieczniejsze niż weak?

Gdy gwarancja czasu życia jest absolutna i oczywista — unowned jest bezpieczniejsze z punktu widzenia projektu: nie wymaga unwrap, nie może być nil, nie maskuje błędów. Jeśli obiekt nie może istnieć bez rodzica, unowned czyni to jawnym kontraktem, a weak rozmywa gwarancję.

Czy jest różnica w wydajności między unowned a weak?

Tak: unowned jest szybsze, ponieważ nie wymaga dostępu do weak-tablicy runtime dla zerowania. W większości aplikacji różnica jest nieodczuwalna, ale w scenariuszach o wysokim obciążeniu z milionami odwołań unowned może być o 10–20% szybsze przy odczycie.

Jak refaktoring wpływa na unowned gwarancje?

Refaktoring — główne zagrożenie dla unowned. Zmiana czasu życia obiektu (buforowanie, operacje asynchroniczne, ponowne użycie) może naruszyć gwarancję. Kompilator nie ostrzeże. Rozwiązanie: migruj na weak przy zmianie architektury lub dodaj komentarz ostrzegawczy.

Podsumowanie

  • Unowned Reference — nieposiadająca referencja bez zerowania; non-optional, nie zwiększa retain count
  • Gwarancja — wymaga jawnego dowodu, że obiekt żyje nie krócej niż kod, który się do niego odwołuje
  • Składniaunowned let lub unowned var; może być non-optional i optional (Swift 5.0+)
  • Unowned vs Weak — unowned jest szybsze i czystsze, ale weak jest bezpieczniejsze; weak — wybór domyślny
  • Domknięcia — unowned self tylko dla synchronicznych domknięć; asynchroniczne wymagają [weak self]
  • Dokumentowanie — każde unowned powinno mieć komentarz z uzasadnieniem gwarancji
  • Zalecenie — w razie wątpliwości wybieraj weak; unowned — dla jawnych i udokumentowanych kontraktów

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również