← Wszystkie wpisy

Makro @State: co przestaje się kompilować w Xcode 27

Apple otwiera wpis o @State w informacjach o wydaniu iOS 27 opisem błędu, który SwiftUI nosi w sobie od iOS 13:3 „A @State declared with an expression as its initial value used to evaluate the expression each time the view struct re-instantiates. In the case of @State private var model = Model(), this means Model.init() gets called many times throughout the view’s lifetime”.1

Poprawką jest przepisanie od nowa. „Xcode 27 introduces a new @State implementation that avoids this repeated evaluation. This new behavior back-deploys to iOS 17 aligned OSes. The new @State is implemented with a Swift macro. It is largely source compatible with the property wrapper version, with a few exceptions”.1

W tym zdaniu kryje się wyzwalacz. Apple wymienia Xcode, nie deployment target.

W skrócie

  • Xcode 27 implementuje @State na nowo jako makro Swift, a strony symboli Apple opisują to przełączenie z obu stron: strona struktury State mówi „When you build with Xcode 27 or later, the system uses the State() macro instead”, a strona makra State() mówi „When you build with Xcode 26 or earlier, the system uses the State property wrapper instead”.23
  • Deployment target nie pozwala wypisać się z makra. Makro ma tę samą dostępność od iOS 13.0 co property wrapper, który zastępuje, a przełączenie zależy od wersji Xcode, nie od targetu. Część działająca w czasie wykonania jest wdrażana wstecznie tylko do „iOS 17 aligned OSes”, więc projekty wspierające iOS 15 lub 16 dostają zmianę na etapie kompilacji, ale bez tamtej korzyści.
  • Ciche odrzucanie wartości jest stare i niezmienione. Apple pisze, że zachowanie „has not changed because of the macro, but some such cases no longer compile”.1 Makro zamienia błąd, który zjadał wartość z inicjalizatora, w błąd kompilacji.
  • Kompilacja psuje się w dwóch wzorcach: inicjalizator przypisujący wartość do właściwości @State, która ma również wartość początkową w miejscu deklaracji, oraz rozszerzenie wywołujące inicjalizator memberwise syntezowany przez kompilator dla struktury o wyłącznie prywatnych składowych.1 Apple pisze „some such cases”, a nie wszystkie, i nigdzie ich nie wylicza.
  • Przed napisaniem tego tekstu przeprowadziłem audyt czterech wydanych aplikacji: 267 deklaracji @State, z czego 201 z wartością początkową w miejscu deklaracji, zero wystąpień któregokolwiek z psujących się wzorców, jedno otarcie się o problem oraz idiom grep, który na macOS produkuje fałszywie czyste wyniki.6

Wpis znalazł się w informacjach o wydaniu iOS i iPadOS 27, w sekcji SwiftUI, a nie w informacjach o wydaniu Xcode 27, gdzie nie ma odpowiadającej mu pozycji.7 Dziwne miejsce jak na zmianę, którą Apple przypisuje Xcode, i dobry powód, dla którego wiadomość dotrze do ludzi z opóźnieniem.

Błąd wydajnościowy, który Apple naprawiło

Opis starego zachowania jest u Apple wyjątkowo dosadny jak na informację o wydaniu. Model.init() „gets called many times throughout the view’s lifetime”.1 SwiftUI bez przerwy tworzy struktury widoków od nowa, a każde takie utworzenie oznaczało ponowne obliczenie wyrażenia po prawej stronie znaku równości. SwiftUI odrzucał wynik, bo już istniejący stan wygrywa, ale praca i tak została wykonana.

Strona makra formułuje nowy kontrakt w jednym zdaniu: „A State() property instantiates its default value the first time SwiftUI instantiates the view”.2

Strona aktualizacji SwiftUI dodaje zastrzeżenie, którego brakuje w informacji o wydaniu, i to właśnie wokół tego zastrzeżenia warto planować: „Build your project in Xcode 27 or later so that the @State attribute uses the State() macro to create a state value in an App, Scene, or View. This change only initializes and stores your property once when it’s a class”.4

„When it’s a class” znacząco zawęża zysk i celuje prosto we wzorzec, którym nowoczesne bazy kodu SwiftUI są przesiąknięte. Przechowywanie obiektu @Observable w @State to udokumentowane podejście Apple, a przykład na stronie samego makra trzyma w ten sposób @Observable class Library.2 Inicjalizator struktury jest zwykle tani. Inicjalizator klasy, który otwiera magazyn danych, uruchamia zapytanie albo rejestruje obserwatora, tani nie jest — a Apple pisze, że wykonywał się „many times”.1

Co się naprawdę zmieniło, a co nie

Apple opisuje semantykę i zachowanie kompilatora w jednym zdaniu, którego dwie połowy prowadzą w przeciwne strony: „If you provide an initial value at @State declaration, and also try to assign a value to it in an initializer, the initializer value is discarded. This behavior has not changed because of the macro, but some such cases no longer compile”.1

Znaczenie kodu nie zmieniło się ani trochę. Pod rządami property wrappera inicjalizator przypisujący wartość do właściwości @State, która miała wartość w miejscu deklaracji, nie robił nic — po cichu — i kompilował się czysto. Makro zostawia regułę w spokoju, a odbiera ciszę.

Wycofany scenariusz awarii był tym kosztownym. Programista pisze inicjalizator, przepuszcza przez niego tytuł, patrzy, jak renderuje się niewłaściwy tytuł, i rusza na polowanie w treści widoku. Kompilator wiedział o wszystkim od początku i nie miał jak tego powiedzieć.

Przykład Apple zawiera dwa komentarze, o które w tym wszystkim chodzi:

struct StickerPageView: View {
    @State private var page = StickerPage()
    let title: String

    init(title: String) {
        // `title` won't have any effect
        // this also won't compile with @State macro
        self.page = StickerPage(title: title)
        self.title = title
    }
}

„Won’t have any effect” i „won’t compile” leżą w sąsiadujących liniach. Pierwsze opisuje Xcode 26. Drugie — Xcode 27. Ten sam kod, to samo znaczenie, inny werdykt.

Poprawka usuwa wartość z miejsca deklaracji:

struct StickerPageView: View {
    @State private var page: StickerPage // no initial value expression
    let title: String

    init(title: String) {
        self.page = StickerPage(title: title) // works!
        self.title = title
    }
}

Apple sprowadza regułę do jednej instrukcji: „When assigning initial value via an initializer, do not provide an initial value at the @State declaration”.1

Trafne podsumowanie nie brzmi więc: makro zepsuło przypisanie w inicjalizatorze. Przypisanie w inicjalizatorze było zepsute już wcześniej, a makro jest pierwszą rzeczą, która mówi to na głos. Kto przedstawia tę zmianę jako regresję, ma kierunek odwrócony — choć praktyczna konsekwencja dla gałęzi wydania jest identyczna: kompilacje, które przechodziły wczoraj, dziś padają.

Jedno zastrzeżenie warto nieść dalej. Apple napisało „some such cases”, a nie wszystkie, i nigdzie ich nie wylicza. Czysta kompilacja pod Xcode 27 to dowód na temat Państwa kodu, a nie dowód na temat reguły.

Syntezowany inicjalizator znika

Drugi wyjątek nie ma nic wspólnego z wartościami początkowymi i łapie kod, który w miejscu wywołania w ogóle nie wspomina o @State.

„When all stored members of a struct are private, the compiler synthesizes a private init that can be used in an extension of the same type:”1

struct StickerPageView: View {
    @State private var page: StickerPage
    private let title: String
    ...
}

extension StickerPageView {
    init(title: String, _ page: StickerPage) {
        self.init(page: page, title: title) // using the synthesized init
    }
}

„The state macro disables this synthesized initializer. So the code above no longer compiles. To mitigate, assign value to members explicitly:”1

extension StickerPageView {
    init(title: String, _ page: StickerPage) {
        self.title = title
        self.page = page
    }
}

Ten wzorzec jest paskudniejszy do znalezienia niż pierwszy, bo psujące się miejsce wywołania siedzi w innej deklaracji niż @State, który je powoduje. Szukanie @State grepem go nie ujawni.

Apple podaje skutek i na tym poprzestaje. Opublikowana deklaracja makra pasuje do objawu:

@attached(accessor, names: named(init), named(get), named(set))
@attached(peer, names: prefixed(`_`), prefixed(`__`), prefixed(`$`))
macro State()

Makro typu accessor dostarczające get i set zmienia to, czym właściwość jest z punktu widzenia kompilatora, a synteza inicjalizatora memberwise opiera się na właściwościach przechowywanych.2 Odczytanie tej deklaracji jako przyczyny to mój wniosek, nie twierdzenie Apple, a obejście i tak nie zależy od mechanizmu: wystarczy wypisać przypisania ręcznie.

Wnioskowanie o typach generycznych i składanie property wrapperów

Pozostałym wyjątkom Apple poświęca po jednym zdaniu i oba zasługują na notkę w liście kontrolnej migracji, choć żaden nie dotknie wielu projektów.

Wnioskowanie o typach generycznych jest potraktowane najbardziej mgliście ze wszystkiego w tym wpisie: „In rare situations, the automatic inference of generic arguments of @State is less flexible with the macro implementation. Write the type with more specificity”.1 Apple nie podaje żadnego przypadku ani komunikatu diagnostycznego, którego można by wypatrywać. Obejściem jest jawna adnotacja typu przy deklaracji, stosowana wszędzie tam, gdzie kompilator zaprotestuje.

Składanie Apple przedstawia jako ograniczenie, a nie jako zerwanie: „Composing @State with other property wrappers or macros is not supported”.1 Warto sprawdzić, jeśli kiedykolwiek opakowali Państwo @State we własny property wrapper, i warto pamiętać, że Apple formułuje to jako obszar niewspierany, a nie jako coś, co kiedyś działało.

Żaden deployment target nie wypisze się z tej zmiany

Trzy zdania zaczerpnięte z trzech stron Apple zamykają każdą drogę ucieczki.

Symbol makra State() ma dostępność od iOS 13.0, iPadOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0 i visionOS 1.0, czyli dokładnie taką jak property wrapper, który zastępuje — obniżenie minimum nie pozwala więc uniknąć makra.23 A przełączenie zależy od kompilatora, nie od targetu: „When you build with Xcode 27 or later, the system uses the State() macro instead”.3

Część zmiany działająca w czasie wykonania ma próg, którego część kompilacyjna nie ma. Apple pisze, że nowe zachowanie „back-deploys to iOS 17 aligned OSes”, co zostawia lukę poniżej: projekt celujący w iOS 15 lub 16 dostaje makro na etapie kompilacji, a wraz z nim wyjątki od zgodności źródłowej, ale bez wstecznie wdrożonego zachowania w czasie wykonania.1 Apple nie mówi, co takie targety dostają w zamian. Przy wsparciu systemu starszego niż iOS 17 należy traktować zerwaną kompilację jako pewnik, a poprawkę powtarzanej inicjalizacji jako niepotwierdzoną na najstarszych urządzeniach.

Wystarczy otworzyć projekt w Xcode 27 i zbudować go — nowy @State już działa. W decyzję nie wchodzi żaden klucz Info.plist, żadne ustawienie kompilacji ani żadne sprawdzenie dostępności.

Cykl 27 niesie trzy zmiany łamiące zgodność, które programiści uparcie wrzucają do jednego worka, a które uderzają w trzech różnych momentach. Wymóg ekranu startowego wiąże „apps built with the 27.0 SDK or later”, a jego ceną jest odrzucenie w App Store. Nakaz cyklu życia sceny wiąże aplikacje „built with the latest SDK”, a jego ceną jest aplikacja, która się nie uruchamia. Makro @State wiąże wersję Xcode, a jego ceną jest nieudana kompilacja. Apple formułuje dwie pierwsze względem SDK, a trzecią względem toolchainu, co stawia @State na początku kolejki: spotykają go Państwo przy pierwszej kompilacji, zanim jeszcze dotkną klucza w pliku plist czy deployment target.

Presja, by otworzyć ten toolchain, przychodzi wedle opublikowanego harmonogramu — choć dla iOS 27 jeszcze go nie ma. Strona wymagań Apple mówi obecnie: „Since April 28, 2026 Apps uploaded to App Store Connect must be built with Xcode 26 or later using an SDK for iOS 26, iPadOS 26, tvOS 26, visionOS 26, or watchOS 26”.5 Apple nie opublikowało żadnej równoważnej daty dla SDK iOS 27. Minimum SDK Apple podnosiło każdej z ostatnich wiosen, więc termin dla 27 jest rozsądnym oczekiwaniem, a nie faktem, i każda konkretna data, którą znajdą Państwo gdzie indziej, jest domysłem.

Co naprawdę zawierają cztery wydane aplikacje

Audyt przeprowadziłem na własnym kodzie, zanim zabrałem się do pisania o cudzym: cztery aplikacje z App Store, wszystkie w SwiftUI, wszystkie budowane obecnie w Xcode 26.6.6

Aplikacja Pliki Swift Deklaracje @State Z wartością w miejscu deklaracji Typy deklarujące @State
Reps 77 120 83 31
Return 57 57 42 14
Ace Citizenship 26 63 54 11
Banana List 55 27 22 8
Razem 215 267 201 64

Pracę zawężają dwa polecenia. Pierwsze znajduje deklaracje @State z wartością początkową, a klasa znaków po @State zarabia na swoje miejsce: [^A-Za-z0-9_] trzyma @StateObject z dala od wyników, czego zwykłe wyszukiwanie @State nie robi.

grep -rn --include="*.swift" \
  --exclude-dir=.build --exclude-dir=DerivedData --exclude-dir=build \
  -E '@State[^A-Za-z0-9_][^=]*[^!<>=]=[^=]' .

Polecenie zakłada, że atrybut i deklaracja są w tej samej linii. Właściwość zapisana z @State we własnej linii nad private var page = StickerPage() nie da żadnego trafienia, co jest tym samym błędem fałszywej czystości, który opisuję niżej, tylko w innym przebraniu. Pominięcia należy czytać jako „jeszcze niesprawdzone”, nie jako „czyste”.

Drugie zawęża do plików, które deklarują również inicjalizator — jedynego miejsca, gdzie pierwszy wyjątek może ugryźć:

find . -name "*.swift" -not -path "*/build/*" -not -path "*/DerivedData/*" -print0 |
while IFS= read -r -d '' f; do
  grep -qE '@State[^A-Za-z0-9_][^=]*[^!<>=]=[^=]' "$f" || continue
  grep -qE '^[[:space:]]*(private |public |internal |fileprivate )?init[[:space:]]*[(<]' "$f" || continue
  echo "$f"
done

Pętla wygląda ciężej niż przepuszczenie tego przez xargs, ale na macOS zarabia na swoją wagę. BSD-owy grep nie emituje separatorów NUL dla -Z tak, jak robi to GNU-owy grep, więc grep -rlZ ... | xargs -0 grep -l podaje drugiemu grep-owi jedną bryłę sklejoną znakami nowej linii. W projekcie, którego ścieżka zawiera spację — na przykład Banana List — dostają Państwo ekran komunikatów „No such file or directory” na standardowym wyjściu błędów i zupełnie nic na standardowym wyjściu, co wygląda dokładnie jak czysty audyt.6 Odczytanie pustego wyjścia jako „brak trafień” daje odwrotną odpowiedź akurat w tych projektach, które najprawdopodobniej jej potrzebują.

Na 215 plików Swift lista skrócona objęła 20 pozycji: dziewięć w Reps, sześć w Return, trzy w Ace Citizenship i dwie w Banana List. Ręczne przeczytanie całej dwudziestki dało ten sam wynik we wszystkich czterech projektach.

  • Pierwszy kształt dokładnie taki, jak opisuje Apple, czyli wartość początkowa w miejscu deklaracji plus przypisanie do tej samej właściwości wewnątrz inicjalizatora tego samego typu: zero.
  • Drugi wyjątek, czyli rozszerzenie wywołujące syntezowany inicjalizator memberwise struktury deklarującej @State: zero.
  • Wyjątek składania, czyli @State obok innego property wrappera lub makra w jednej deklaracji: zero.

Jedno otarcie się o problem zasługuje na opis, bo dzieli je jedna linia od kształtu, który Apple każe usunąć. Widok konfiguracji profilu w Reps deklaruje @State private var healthWriteStatus: HealthAuthorizationState = .notRequested, a następnie w swoim inicjalizatorze przypisuje self._healthWriteStatus = State(initialValue: ...). Wartość jest w obu miejscach, więc zdanie Apple o obejściu pasuje tu co do słowa: nie należy podawać wartości początkowej przy deklaracji @State.1 Przypisanie używa formy z podkreśleniem, a nie formy z wartością opakowaną z przykładu Apple, a informacja o wydaniu w ogóle nie wspomina o formie z podkreśleniem.

I tu zostaje pytanie, na które mój audyt nie umiał odpowiedzieć. Idiom _x = State(initialValue:) pojawia się 15 razy w trzech z czterech aplikacji i pozostaje standardowym sposobem zasilania stanu z parametru inicjalizatora. Wpis Apple się do niego nie odnosi. Deklaracja makra rzeczywiście generuje towarzyszący symbol (peer) z przedrostkiem podkreślenia,2 co jest sugestywne, ale nie jest gwarancją. Buduję w Xcode 26.6 (build 17F113), więc nie mogłem zweryfikować ani samego idiomu, ani treści wynikających komunikatów o błędzie kompilacji.6 Każdy, kto ma betę Xcode 27, rozstrzygnie oba pytania w jedno popołudnie. Zanim ktoś to zrobi, warto przeszukiwać kod pod kątem kształtu deklaracji, a nie pod kątem treści błędu.

Uczciwy nagłówek płynący z 267 deklaracji brzmi tak: większość kodu SwiftUI przechodzi nietknięta, co zgadza się z formułą Apple: „largely source compatible”.1 Zagrożone są widoki z ręcznie pisanymi inicjalizatorami, a te skupiają się mocno: mniej niż jeden plik Swift na 10 w czterech bazach kodu zawierał jednocześnie ręcznie napisany inicjalizator i @State z własną wartością początkową.

FAQ

Czy muszę zmienić wywołania _page = State(initialValue:)?

Wpis Apple tego nie mówi. Forma z podkreśleniem przypisuje bezpośrednio do rzutowanej pamięci zamiast do wartości opakowanej i nigdzie nie występuje w informacji o wydaniu: żadnego initialValue, żadnego przykładu z podkreśleniem, ani słowa w jedną czy w drugą stronę.1 Opublikowana deklaracja makra faktycznie emituje towarzyszący symbol z przedrostkiem _, co jest sugestywne, ale nie jest gwarancją.2 Trzy z czterech audytowanych przeze mnie aplikacji korzystają z tego idiomu, łącznie 15 razy, więc odpowiedź ma znaczenie dla większej liczby baz kodu niż oba udokumentowane wyjątki.6 Zanim Apple się do tego odniesie, warto zbudować projekt w Xcode 27 i pozwolić odpowiedzieć kompilatorowi, zamiast refaktoryzować na podstawie domysłów.

Czy makro zmieniło to, co dzieje się z wartością przypisaną w inicjalizatorze?

Nie. Apple wyraża się jasno, że zachowanie odrzucania „has not changed because of the macro, but some such cases no longer compile”.1 Pod Xcode 26 inicjalizator przypisujący wartość do właściwości @State, która miała już wartość w miejscu deklaracji, nie robił nic i kompilował się. Pod Xcode 27 część takich przypadków przestaje się budować. Semantyka została na miejscu, a przybyła diagnostyka — zepsuta kompilacja to więc kompilator zgłaszający błąd, który już wcześniej był w kodzie.

Jak znaleźć zagrożony kod w swoim projekcie?

Należy wyszukać deklaracje @State z wartością początkową, zawęzić wyniki do plików, które deklarują także inicjalizator, a potem przeczytać tę krótką listę ręcznie. @StateObject warto wykluczyć klasą znaków (@State[^A-Za-z0-9_]), a na macOS lepiej użyć pętli find -print0 niż grep -rlZ | xargs -0, bo BSD-owy grep nie emituje separatorów NUL, a każda ścieżka zawierająca spację daje puste wyjście wyglądające jak zaliczenie.6 W czterech aplikacjach i 215 plikach Swift lista skrócona objęła 20 plików. Osobno warto poszukać rozszerzeń, które wywołują self.init(...) na strukturze widoku, bo drugi wyjątek nie zostawia żadnego śladu w pobliżu @State, który go powoduje.

Czy moja aplikacja faktycznie przyspieszy?

Tylko w określonych okolicznościach, i Apple zawęża je bardziej, niż sugeruje informacja o wydaniu. Informacja o wydaniu opisuje unikanie powtarzanego obliczania w ogólności,1 podczas gdy wpis w aktualizacjach SwiftUI mówi, że zmiana „only initializes and stores your property once when it’s a class”.4 Zysk ląduje na @State private var model = SomeObservableClass(), gdzie stara implementacja wykonywała inicjalizator klasy przy każdym ponownym utworzeniu widoku i wyrzucała wynik. @State private var isPresented = false nigdy nie był problemem.

Najważniejsze wnioski

Dla programistów iOS: - Audytować należy dwa kształty, nie jeden. Pierwszy siedzi przy deklaracji @State obok inicjalizatora; drugi — w rozszerzeniu wywołującym self.init(...) na strukturze widoku, której wszystkie przechowywane składowe są prywatne.1 - Pierwszy naprawia się przez usunięcie wartości z miejsca deklaracji, a nie przez usunięcie przypisania w inicjalizatorze. Instrukcja Apple mówi, by zachować inicjalizator jako jedyne źródło, a deklarację zostawić bez wartości.1

Dla zespołów utrzymujących starszy kod SwiftUI: - Czas przeglądu warto zaplanować pod listę skróconą, nie pod całą bazę kodu. Plików zawierających jednocześnie @State z wartością początkową i ręcznie napisany inicjalizator było w moich czterech aplikacjach 20 na 215, a każde wystąpienie pierwszego wzorca musi znajdować się w którymś z nich. Drugiego wzorca należy szukać osobno, bo kryje się w rozszerzeniach.6 - Zerwaną kompilację warto traktować jako znaleziony błąd. SwiftUI już wcześniej odrzucał wartość z inicjalizatora, którą kompilator teraz zgłasza jako błąd — wszędzie więc, gdzie zmiana gryzie, coś już wcześniej działało źle.1

Dla osób odpowiedzialnych za wydania: - Audyt @State warto zaplanować przed pracami wyzwalanymi przez SDK w tym samym cyklu. Klucz ekranu startowego i cykl życia sceny obydwa wiążą SDK, względem którego budują Państwo projekt; @State wiąże Xcode, w którym Państwo budują, więc ląduje pierwszy.13 - Nie należy planować pod termin dla SDK iOS 27. Opublikowanym minimum Apple pozostaje SDK iOS 26, wymagany od 28 kwietnia 2026, a dla 27 Apple nie ogłosiło niczego.5


Trzy punkty egzekwowania wchodzą w jednym cyklu, a zawodzą w trzech różnych miejscach: klucz ekranu startowego zatrzymuje zgłoszenie, nakaz dotyczący scen zatrzymuje uruchomienie, a makro @State zatrzymuje kompilację. Po resztę tego, co ląduje w tym samym SDK, proszę sięgnąć do Co nowego w SwiftUI dla iOS 27. Centrum całej serii to Seria Ekosystem Apple.

Źródła


  1. Apple, iOS & iPadOS 27 Release Notes, sekcja SwiftUI, New Features (radar 105893279). Źródło opisu starego zachowania („A @State declared with an expression as its initial value used to evaluate the expression each time the view struct re-instantiates. In the case of @State private var model = Model(), this means Model.init() gets called many times throughout the view’s lifetime”), nowej implementacji („Xcode 27 introduces a new @State implementation that avoids this repeated evaluation. This new behavior back-deploys to iOS 17 aligned OSes. The new @State is implemented with a Swift macro. It is largely source compatible with the property wrapper version, with a few exceptions”), pierwszego wyjątku wraz z instrukcją („If you provide an initial value at @State declaration, and also try to assign a value to it in an initializer, the initializer value is discarded. This behavior has not changed because of the macro, but some such cases no longer compile” oraz „When assigning initial value via an initializer, do not provide an initial value at the @State declaration”), obu listingów kodu StickerPageView dla pierwszego wyjątku, drugiego wyjątku („When all stored members of a struct are private, the compiler synthesizes a private init that can be used in an extension of the same type” oraz „The state macro disables this synthesized initializer. So the code above no longer compiles. To mitigate, assign value to members explicitly”) wraz z dwoma listingami kodu, notki o wnioskowaniu o typach generycznych („In rare situations, the automatic inference of generic arguments of @State is less flexible with the macro implementation. Write the type with more specificity”) oraz notki o składaniu („Composing @State with other property wrappers or macros is not supported”). Wszystkie listingi kodu odtworzone dosłownie. Zweryfikowane na podstawie JSON-a dokumentacji Apple 25 lipca 2026, ponieważ strona HTML renderuje swoją treść przez JavaScript. 

  2. Apple, State() macro, dokumentacja makra SwiftUI. Źródło opublikowanej deklaracji (@attached(accessor, names: named(init), named(get), named(set)), @attached(peer, names: prefixed(_), prefixed(__), prefixed($)), macro State()), listy dostępności (iOS 13.0, iPadOS 13.0, Mac Catalyst 13.0, macOS 10.15, tvOS 13.0, visionOS 1.0, watchOS 6.0), uwagi o toolchainie („When you build with Xcode 26 or earlier, the system uses the State property wrapper instead”), nowego kontraktu inicjalizacji („A State() property instantiates its default value the first time SwiftUI instantiates the view”) oraz przykładu „Store observable objects” trzymającego @Observable class Library w @State

  3. Apple, State, dokumentacja struktury SwiftUI. Nadal zadeklarowana jako @frozen @propertyWrapper struct State<Value> z dostępnością od iOS 13.0, iPadOS 13.0, Mac Catalyst 13.0, macOS 10.15, tvOS 13.0, visionOS 1.0 i watchOS 6.0. Źródło uwagi o toolchainie wskazującej w drugą stronę: „When you build with Xcode 27 or later, the system uses the State() macro instead”. 

  4. Apple, SwiftUI Updates, czerwiec 2026, General. Źródło zastrzeżenia o klasie: „Build your project in Xcode 27 or later so that the @State attribute uses the State() macro to create a state value in an App, Scene, or View. This change only initializes and stores your property once when it’s a class”. 

  5. Apple, Upcoming requirements, Apple Developer News. Źródło aktualnego minimum SDK: „Since April 28, 2026 Apps uploaded to App Store Connect must be built with Xcode 26 or later using an SDK for iOS 26, iPadOS 26, tvOS 26, visionOS 26, or watchOS 26”. Sprawdzone 25 lipca 2026; strona nie wymienia żadnego wymogu odnoszącego się do SDK iOS 27. 

  6. Autorski audyt czterech wydanych aplikacji SwiftUI (Reps, Return, Ace Citizenship i Banana List) na macOS 26.5.2 z Xcode 26.6 (build 17F113), 25 lipca 2026. Liczby pochodzą ze skryptu, który parsuje każdą deklarację typu po głębokości nawiasów klamrowych i ogranicza ciała inicjalizatorów do jej wnętrza, skonfrontowanego z opublikowanym wyżej poleceniem grep, które odtworzyło liczby deklaracji z wartością początkową dokładnie we wszystkich czterech projektach (83, 42, 54 i 22). Zachowanie BSD-owego grep potwierdzono bezpośrednio: na macOS grep -rlZ emituje wyjście rozdzielone znakami nowej linii zamiast znakami NUL, więc xargs -0 otrzymuje jeden sklejony argument, a potok kończy się komunikatem „No such file or directory” dla każdej ścieżki zawierającej spację. Liczba wystąpień idiomu _x = State(initialValue:) (15 w Reps, Return i Banana List) pochodzi z tego samego przebiegu. Zachowania pod Xcode 27 nie testowano i nie podaje się tu treści żadnych błędów kompilacji, ponieważ na użytej maszynie Xcode 27 nie był zainstalowany. 

  7. Apple, Xcode 27 Release Notes. Przeszukane pod kątem radaru 105893279 oraz jakiegokolwiek wpisu opisującego makro @State 25 lipca 2026; nie ma żadnego z nich. Jedyna wzmianka o @State dotyczy niepowiązanej poprawki MusicKit (radar 176947544). 

Powiązane artykuły

Xcode 27 usuwa ld64 i wymaga unikalnych nazw modułów

Xcode 27 usuwa linker ld64 i wymaga unikalnych nazw modułów Clang. Oba pęknięcia widać przy aktualizacji toolchaina: aud…

20 min czytania

Ekran startowy w iOS 27: cztery klucze albo odrzucenie

Aplikacje budowane z SDK z iOS 27 muszą deklarować ekran startowy, inaczej App Store je odrzuci. Oto cztery klucze i spo…

12 min czytania