.onAppear — modyfikator SwiftUI, który wykonuje domknięcie podczas dodawania View do hierarchii interfejsu. Wywołanie następuje jednokrotnie na pojawienie się instancji na ekranie i służy jako główny punkt do ładowania danych, uruchamiania animacji i wysyłania zdarzeń analitycznych. Według Apple Developer Documentation (2026), onAppear gwarantuje wykonanie przed pierwszym renderowaniem, ale nie gwarantuje wywołania przy każdym ponownym pokazaniu, jeśli View pozostaje w pamięci. Więcej o SwiftUI przeczytasz w materiałach o SwiftUI.
Najważniejsze
.onAppear — modyfikator View w SwiftUI, który przyjmuje domknięcie Void i wykonuje je w momencie, gdy View staje się widoczne na ekranie. Ten modyfikator jest częścią systemu cyklu życia komponentów SwiftUI obok .onDisappear i .task. Apple wprowadziła onAppear wraz z wydaniem SwiftUI w iOS 13 i watchOS 6 jako zamiennik viewDidLoad z UIKit.
Składniowo .onAppear modyfikuje dowolną View i zwraca tę samą View z dołączonym działaniem. Kompilator SwiftUI wywołuje przekazane domknięcie jeden raz, gdy widok zostaje dodany do hierarchii i przechodzi etap renderowania. Jeśli View zostanie usunięta i ponownie dodana (na przykład podczas przewijania listy), onAppear wywoływany jest ponownie — to zachowanie często staje się źródłem nieoczekiwanych błędów.
Podstawowa składnia modyfikatora jest minimalistyczna: onAppear bez parametrów. W SwiftUI nie ma możliwości przekazania priorytetu lub animacji — domknięcie wykonuje się synchronicznie w głównym wątku natychmiast po renderowaniu.
struct ContentView: View {
var body: some View {
Text("Witaj, SwiftUI!")
.onAppear {
print("Widok pojawił się na ekranie")
}
}
}
Ograniczenia: onAppear nie obsługuje bezpośrednio async/await. Dla operacji asynchronicznych wewnątrz domknięcia potrzebny jest Task {} lub osobna funkcja z async/await wywoływana przez Task.detached. To sprawia, że onAppear jest mniej wygodny dla zapytań sieciowych w porównaniu z modyfikatorem .task.
.onAppear wbudowuje się w potok renderowania SwiftUI na etapie layout+render. Gdy SwiftUI oblicza ciało View i wykrywa zmianę hierarchii, uruchamia callbacki onAppear dla wszystkich nowo dodanych widoków. Kolejność wywołania odpowiada kolejności zagnieżdżenia: najpierw onAppear u rodzica, potem u elementów potomnych.
Ważna cecha SwiftUI — onAppear nie jest powiązany z pojawieniem się na fizycznym ekranie. Modyfikator wywoływany jest, gdy View zostaje dodana do hierarchii niezależnie od tego, czy jest widoczna dla użytkownika (na przykład poza ekranem w ScrollView). To odróżnia SwiftUI od UIKit, gdzie viewWillAppear działa tylko przy rzeczywistym pojawieniu.
Kolejność wywołania podlega zasadzie parent-first: VStack lub NavigationView najpierw otrzymuje onAppear, potem każdy element potomny po kolei. Jest to krytyczne dla inicjalizacji współdzielonych zasobów: jeśli elementy potomne zależą od danych ładowanych przez rodzica, powinny sprawdzać dostępność przez Optional.
struct ParentView: View {
var body: some View {
VStack {
ChildView()
ChildView()
}
.onAppear {
print("Parent onAppear — pierwszy")
}
}
}
struct ChildView: View {
var body: some View {
Text("Dziecko")
.onAppear {
print("Child onAppear")
}
}
}
Wynik w konsoli będzie: Parent onAppear — pierwszy, następnie dwukrotnie Child onAppear w kolejności położenia. To zachowanie jest gwarantowane przez Apple i stabilne we wszystkich wersjach SwiftUI (iOS 13–18).
.onAppear ma kilka scenariuszy wywołania, które zależą od kontenera i nawigacji. W NavigationStack onAppear działa przy każdym push nowego kontrolera i przy pop — dla kontrolera głównego. W TabView przełączanie zakładek wywołuje onAppear dla wyświetlanej zakładki i onDisappear dla ukrytej.
W List i ScrollView onAppear wywoływany jest dla komórek, które trafiły w obszar widoczności lub znajdują się w buforze wstępnego renderowania. iOS 18 wprowadził mechanizm prefetch, który może wywołać onAppear dla komórek 2–3 ekrany przed przewinięciem — to przyspiesza odbiór, ale może prowokować zbędne zapytania sieciowe.
NavigationStack (iOS 16+) zarządza stosem ekranów inaczej niż NavigationView. Przy push nowego ekranu onAppear działa tylko u nowego ekranu, a bieżący nie otrzymuje onDisappear aż do rzeczywistego usunięcia. Przy pop następuje proces odwrotny: onDisappear u opuszczanego ekranu, onAppear u powracającego.
| Scenariusz | onAppear | onDisappear |
|---|---|---|
| Push | Nowy ekran | Nie (ekran pozostaje w stosie) |
| Pop | Powracający ekran | Opuszczany ekran |
| Tab switch | Nowa zakładka | Stara zakładka |
| Sheet dismiss | Ekran nadrzędny | Otwarty sheet |
Praktyczne zastosowanie onAppear obejmuje trzy główne kategorie: ładowanie danych, uruchamianie animacji i wysyłanie analityki. Każdy scenariusz wymaga uwzględnienia cech cyklu życia SwiftUI, aby uniknąć duplikujących się wywołań i wycieków pamięci.
Ładowanie danych — najczęstszy scenariusz onAppear. Wewnątrz domknięcia tworzony jest Task dla wywołania async, a wynik zapisywany jest w @State lub @StateObject. Ważne jest sprawdzenie, czy dane nie są ładowane ponownie, używając flagi isLoading lub sprawdzenia na nil.
struct ProfileView: View {
@StateObject private var viewModel = ProfileViewModel()
var body: some View {
VStack {
if viewModel.isLoading {
ProgressView()
} else {
Text(viewModel.userName)
}
}
.onAppear {
guard viewModel.userName == nil else { return }
Task {
await viewModel.loadProfile()
}
}
}
}
Guard against re-fetch — krytyczna praktyka. Jeśli SwiftUI odtworzy View (na przykład przy obrocie ekranu), onAppear wywoła się ponownie bez guard. Alternatywą jest modyfikator .task, który automatycznie anuluje poprzednie zapytanie.
Animacja wejścia używa onAppear do zmiany zmiennych stanu, które wyzwalają animację przez withAnimation lub modyfikator animation. Typowy wzorzec: stan początkowy (opacity 0, offset 100), przejście do końcowego (opacity 1, offset 0) przy pojawieniu.
struct AnimatedCard: View {
@State private var isVisible = false
var body: some View {
RoundedRectangle(cornerRadius: 12)
.fill(Color.blue)
.opacity(isVisible ? 1 : 0)
.offset(y: isVisible ? 0 : 50)
.animation(.spring(), value: isVisible)
.onAppear {
withAnimation(.spring().delay(0.3)) {
isVisible = true
}
}
}
}
Opóźnienie 0.3 sekundy tworzy efekt sekwencyjnego pojawiania się, jeśli na ekranie jest kilka takich kart. Dla listy animowanych elementów użyj indeksu elementu jako mnożnika opóźnienia.
.task — modyfikator SwiftUI dodany w iOS 15, który rozwiązuje problem operacji asynchronicznych w onAppear. W przeciwieństwie do onAppear, .task przyjmuje async-domknięcie, automatycznie zarządza jego cyklem życia i anuluje je przy znikaniu View. Podczas gdy onAppear wykonuje się synchronicznie, .task uruchamia operację asynchroniczną i pozwala SwiftUI anulować ją przy onDisappear.
Główna różnica — zarządzanie anulowaniem. Gdy .task tworzy operację async, SwiftUI zachowuje referencję do Task i automatycznie wywołuje cancel() przy usunięciu View z hierarchii. onAppear z Task {} wewnątrz nie anuluje uruchomionej operacji — kontynuuje ona działanie nawet po zniknięciu View, co może spowodować stan wyścigu lub zapis do już zwolnionej instancji.
| Cecha | .onAppear | .task |
|---|---|---|
| Wersja iOS | iOS 13+ | iOS 15+ |
| Obsługa async | Tylko przez Task {} | Natywny async/await |
| Autoanulowanie | Nie | Przy znikaniu View |
| Ponowne wywołanie | Przy każdym pojawieniu | Domyślnie jednokrotnie |
| Kod synchroniczny | Tak | Tylko async |
Wybór modyfikatora: dla działań synchronicznych (animacje, analityka, logi) używaj onAppear. Dla asynchronicznego ładowania danych (API, Core Data, system plików) preferowany jest .task — jest bezpieczniejszy i czystszy.
Błąd 1: wielokrotne wywołanie z powodu odtworzenia View. Gdy SwiftUI odtwarza ciało View (zmiana @State, obrót ekranu), onAppear może wywołać się ponownie. Rozwiązaniem jest dodanie flagi ładowania lub użycie .equatable() aby zapobiec zbędnym przerysowaniom. Według SwiftLee (2025), 40% błędów SwiftUI w produkcji jest związanych właśnie z ponownymi wywołaniami onAppear.
Błąd 2: wyciek pamięci przez mocną referencję. Jeśli domknięcie onAppear przechwytuje self bez słabej referencji, powstaje retain cycle z View. SwiftUI nie gwarantuje zerowania przechwyconych obiektów przy znikaniu View. Użyj capture list [weak self] dla ViewModel lub serwisów.
Błąd 3: wykonanie w wątku tła. onAppear wykonuje się w głównym wątku — jest to poprawne dla operacji UI. Ale jeśli wewnątrz onAppear uruchamiany jest Task, upewnij się, że aktualizacja @State następuje przez MainActor.run. Swift 5.9 i nowsze automatycznie powracają na MainActor, ale lepiej wskazać @MainActor jawnie.
Wzorzec z flagą ładowania to najbezpieczniejszy sposób ochrony przed duplikowaniem. Przechowuj flagę w @State lub @StateObject i resetuj ją tylko przy ręcznej aktualizacji. Alternatywą jest użycie .task zamiast onAppear: .task domyślnie nie restartuje się przy przerysowaniu, jeśli operacja async już działa.
struct SafeView: View {
@State private var hasAppeared = false
@State private var items: [Item] = []
var body: some View {
List(items, id: \.id) { item in
Text(item.name)
}
.onAppear {
guard !hasAppeared else { return }
hasAppeared = true
Task {
items = await DataService.shared.fetchItems()
}
}
}
}
Często zadawane pytania
viewDidLoad wywoływany jest jeden raz w ciągu życia UIViewController, niezależnie od widoczności. .onAppear wywoływany jest przy każdym dodaniu View do hierarchii — jeśli View zostanie usunięta i ponownie dodana, onAppear działa od nowa. W NavigationView viewDidLoad wywoływany jest przy inicjalizacji, a onAppear — przy każdym pokazaniu ekranu.
Tak, przez otoczkę Task { await asyncFunction() }. Jednak dla operacji async preferowany jest .task, który automatycznie zarządza anulowaniem i nie wymaga tworzenia Task ręcznie. .task gwarantuje również anulowanie przy znikaniu View, zapobiegając wyciekom.
Powodem jest odtworzenie ciała View z powodu zmiany @State, @Published lub konfiguracji rodzica. SwiftUI może przerysować View w odpowiedzi na zmianę dowolnej obserwowanej właściwości. Dodatkowo LazyVStack i List wywołują onAppear dla komórek, które zbliżają się do widocznego obszaru, i ponownie podczas przewijania w górę.
Tak, .onAppear jest dostępny na wszystkich platformach SwiftUI: iOS 13+, watchOS 6+, tvOS 13+, macOS 10.15+. Działanie jest identyczne: modyfikator wywoływany jest przy dodaniu View do hierarchii. Na watchOS onAppear działa przy aktywacji aplikacji ze stanu oczekiwania, co wymaga uwzględnienia w projekcie.
.onAppear nie przyjmuje parametrów — tylko domknięcie Void. Do przekazania parametrów użyj domknięcia, które przechwytuje zmienne zewnętrzne. Alternatywnym podejściem jest utworzenie własnego modyfikatora onAppear z parametrami przez ViewModifier lub odpowiednik .onChange.
Podsumowanie
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.
Przeczytaj również