Tüm Yazılar
KategoriSwiftUI
Okuma Süresi
11 dk
Yayın Tarihi
2026-06-17
Kelime Sayısı
2.475kelime

Kahveni hazırla - bu içerikli bir makale!

iOS 27'de @State Artık Macro: Kırılan Kod ve Build Kazancı

Özet

SwiftUI iOS 27 State macro ContentBuilder build süresi: @State artık property wrapper değil macro, ViewBuilder ContentBuilder oldu. Kırılan kod, düzeltmesi ve Eylül GA güncellemesi.

iOS 27'de @State Artık Macro: Kırılan Kod ve Build Kazancı

Xcode 27 beta ile gelen SwiftUI değişikliklerinden en çok koda dokunanı budur: @State artık property wrapper değil, bir Swift macro. Bu değişiklik, deklarasyon yerinde başlangıç değeri verip init içinde tekrar atama yapan yaygın bir pattern'i doğrudan kırıyor ve SwiftUI iOS 27 State macro ContentBuilder build süresi tartışmasının merkezine oturuyor. Aynı sürümde @ViewBuilder'ın @ContentBuilder olarak açığa çıkması da tip çıkarımını ve build süresini etkiliyor — bu yazı ikisini birlikte, kod örnekleriyle ele alıyor.

💡 Pro Tip: Xcode 27'ye geçmeden önce projendeki @State deklarasyonlarını tara — deklarasyon yerinde başlangıç değeri VE init içinde tekrar atama olan her yer potansiyel kırılma adayıdır.

İçindekiler

Kök değişiklik: @State artık macro

Apple'ın resmi State dokümanı artık şunu netleştiriyor: Xcode 27 veya sonrasıyla derlediğinde, sistem senin yazdığın @State deklarasyonunun arkasında State() macro'sunu kullanıyor. Dokümanın API imzası hâlâ eski @frozen @propertyWrapper struct State şeklinde basılıyor; macro notu ayrı bir "Important" kutusunda veriliyor — yani görünüşte hiçbir şey değişmemiş gibi duruyor ama derleme zamanı davranışı farklı.

Bunun pratik sonucu şu: macro, senin için gerçek bir "backing storage" (arka plan depolama alanı) sentezliyor. Eskiden property wrapper bunu _name gibi otomatik üretilen bir örnekle yapıyordu; şimdi macro, aynı işi derleme zamanında açılan gerçek kod satırlarıyla yapıyor. Bu fark, bir sonraki bölümdeki kırılmanın kök nedeni.

Kırılan derleme örneği ve düzeltmesi

En sık karşılaşacağın kırılma şu: @State property'sine hem deklarasyon yerinde bir başlangıç değeri veriyorsun hem de init içinde tekrar atama yapıyorsun. Kırılma için view'da ikinci bir stored property şart; hata da @State'i değil, o diğer property'yi adlandırıyor.

swift
1import SwiftUI
2 
3final class StickerPage { var index = 0 }
4 
5struct StickerView: View {
6 let title: String
7 @State private var page = StickerPage()
8 
9 init(title: String, page: StickerPage) {
10 self.page = page // error: variable 'self.title' used before being initialized
11 self.title = title
12 }
13 
14 var body: some View { Text("\(title) — \(page.index)") }
15}

Düzeltme basit: deklarasyon yerindeki başlangıç değerini tamamen kaldır, değeri yalnızca init içinde ver. Sırayı değiştirmek de hatayı susturur, ama değeri sessizce kaybettirir.

swift
1import SwiftUI
2 
3final class StickerPage { var index = 0 }
4 
5struct StickerView: View {
6 let title: String
7 @State private var page: StickerPage
8 
9 init(title: String, page: StickerPage) {
10 self.page = page
11 self.title = title
12 }
13 
14 var body: some View { Text("\(title) — \(page.index)") }
15}

Bir diğer kırılma noktası: bazı view'lar Swift'in extension'dan sentezlediği private memberwise init'e güveniyordu. Bu init artık otomatik olarak bulunamayabiliyor, elle tanımlaman gerekebiliyor. SwiftUI property wrapper'larının genel evrimini daha önce ele almıştık — bu makale, o yazının Xcode 27 beta dönemindeki devamı olarak okunmalı.

Composability sınırı: @State başka wrapper ile birleşmiyor

@State'i başka bir property wrapper ile aynı deklarasyonda birleştirmeye (compose etmeye) çalışmak artık "invalid redeclaration of synthesized property" hatası üretebiliyor. Macro kendi storage'ını sentezlerken, üstüne ikinci bir wrapper'ın da kendi storage'ını sentezlemeye çalışması çakışıyor. Apple bunu bir sınır olarak koyuyor: @State'i diğer wrapper veya macro'larla compose etmek desteklenmiyor. Çözüm genel: backing storage adları çakışmayacak şekilde yeniden yapılandır.

Bu kısıtlama özellikle eski property-wrapper döneminden kalan, birden fazla wrapper'ı zincirleyen yardımcı tiplerde sürpriz yaratabiliyor. Eğer projende @State üzerine kendi yazdığın bir wrapper'ı bindirdiğin bir yer varsa, Xcode 27'ye geçmeden önce o dosyayı özellikle derleyerek kontrol etmen gerekiyor — derleyici hatası net olsa da, hatanın kaynağı ilk bakışta macro genişlemesiyle ilgisiz gibi görünebiliyor.

Üçüncü istisna: generic çıkarımı daralıyor

Apple'ın iOS 27 sürüm notları bir sınır daha belgeliyor: nadir durumlarda @State'in generic argüman çıkarımı macro implementasyonuyla daha az esnek. Belirti generic çıkarım hatası; çözüm tipi daha belirgin yazmak.

Lazy class başlatmanın performans etkisi

WWDC26 SwiftUI rehberi bunu açıkça yazıyor: @State içinde tutulan class'lar artık lazy (tembel) başlatılıyor — view'ın ömrü boyunca yalnızca bir kez. Bunun anlamı şu: @State private var model = Model() gibi bir satır, eskiden view struct'ı her yeniden oluşturulduğunda Model() çağrısını tetikliyordu (SwiftUI fazladan oluşan örnekleri sonradan atsa da, init kodu yine de çalışıyordu). Macro tabanlı yeni implementasyon, bu başlatmayı yalnızca ilk seferde çalıştırıyor.

İki nitelik önemli. Apple'ın güncelleme sayfası kazancı sınırlıyor: property yalnızca bir kez başlatılıp saklanıyor, ama bu yalnızca class olduğunda. Ayrıca davranışı Xcode sürümü belirliyor, deployment target değil; runtime tarafı yalnızca "iOS 17 aligned OSes" hizasına back-deploy ediyor — iOS 15/16 hedefleyen proje kırılma riskini alır, runtime kazancını almaz.

Burada dürüst olmak gerekiyor: Apple'ın kendi rehberi ve topluluk kaynakları bu iyileşmeyi nitel olarak ("improve significantly") anlatıyor, ama kamuya açık, tekrarlanabilir bir yüzde veya milisaniye rakamı hiçbir birincil kaynakta bulunmuyor. Bu makalede uydurma bir benchmark sayısı vermek yerine, bir sonraki bölümde bu iyileşmeyi kendi projende nasıl gözlemleyebileceğini göstereceğiz.

ViewBuilder'dan ContentBuilder'a: neden açıldı

SwiftUI'nin result builder'ları — en görünür olanı @ViewBuilder — artık birleşik @ContentBuilder altında toplanıyor. Bu, Apple'ın ToolbarContentBuilder, CommandsBuilder gibi tip-özel builder'ları tek bir mekanizma altında birleştirme kararının bir parçası.

Değişikliğin asıl etkisi şu: builder'lar artık içeriğin View protokolüne uymasını zorunlu kılmıyor. Bu, SwiftUI dışında kendi DSL'lerini kurmak isteyenler için bir kapı açıyor, ama bedeli de var — bazı ifadelerin tip kontrolü (type-check) şekli değişiyor ve önceden belirsizlik oluşturmayan bazı çağrılar artık "ambiguous" hatası verebiliyor. WWDC26 rehberi bu değişikliğin Xcode 27'de build sürelerini önemli ölçüde iyileştirdiğini belirtiyor; ancak burada da somut bir yüzde rakamı paylaşılmıyor, bu yüzden "önemli ölçüde" ifadesinin ötesine geçmiyoruz.

Swift Macros Deep Dive yazımızda derleme-zamanı kod üretiminin genel mantığını incelemiştik; ContentBuilder da aynı ailenin — derleme zamanında senin yazdığın deklaratif söz dizimini gerçek Swift koduna çeviren mekanizmaların — bir parçası.

Belirsiz tip hatası ve trailing closure ile çözüm

ContentBuilder'ın artık View kısıtı koymaması, somut bir örnekte şu şekilde kendini gösteriyor. Aşağıdaki satır Xcode 27'de artık derlenmiyor:

swift
1Text("Hello")
2 .overlay(Color.blue.opacity(0.70).blendMode(.overlay)) // ambiguous use of 'opacity'

Hata "ambiguous use of 'opacity'" — çünkü derleyici artık hangi overload'ı seçeceğine karar veremiyor. Çözüm, trailing closure formuna geçmek. Bu form, builder tabanlı overload'ı seçiyor ve belirsizliği kırıyor:

swift
1Text("Hello")
2 .overlay { Color.blue.opacity(0.70).blendMode(.overlay) }

Benzer bir çakışma, kendi modülünde Color gibi SwiftUI ile aynı adı taşıyan bir tip tanımladığında da ortaya çıkabiliyor; bu durumda SwiftUI.Color şeklinde tam nitelemek gerekiyor. Deployment target'ı 27'nin altında tutup derin dallanan bir Swift Charts içeriği yazıyorsan, tip kontrolü (type-check) yavaşlayabiliyor — bunun çözümü, dalları ayrı bir fonksiyona çıkarıp @ChartContentBuilder ile işaretlemek:

swift
1@ChartContentBuilder
2func makeBars(for data: [Item]) -> some ChartContent {
3 ForEach(data) { item in
4 BarMark(x: .value("Kategori", item.name), y: .value("Değer", item.value))
5 }
6}

SwiftUI Charts ile Data Visualization yazımızda Charts framework'ünün temel kullanımını anlatmıştık; @ChartContentBuilder optimizasyonu doğrudan o örneklerin üzerine ekleniyor.

Kendi projende build süresini nasıl ölçersin

Apple'ın "önemli ölçüde iyileşme" ifadesini kendi projende doğrulamak istersen, kamuya açık bir benchmark tablosuna güvenmek yerine kendi ölçümünü yap — çünkü build süresi dosya sayısına, view iç içeliğine ve makine gücüne göre değişir. İzleyebileceğin adımlar:

  • Temiz build zamanı al: xcodebuild clean build sonrası time ile ölç, aynı makinede Xcode 26 ve 27 toolchain'i arasında karşılaştır.
  • Macro genişlemesini gözlemle: derleyicinin @State için ürettiği kodu doğrudan görmek istersen aşağıdaki komutu kullanabilirsin.
bash
1swiftc -Xfrontend -dump-macro-expansions ProfileView.swift

Bu komut, macro'nun senin için sentezlediği init-accessorları ve storage alanlarını terminale basıyor — "sihir" değil, sıradan Swift kodu olduğunu bu çıktıda net görürsün.

  • Type-check süresini izole et: -Xfrontend -warn-long-function-bodies=100 bayrağıyla hangi fonksiyon gövdelerinin tip kontrolünde yavaşladığını görebilirsin; Apple build sürelerinin iyileştiğini söylüyor, bu listedeki değişimi kendi projende ölç, varsayma.
  • Sonucu not al: kendi projenin gerçek rakamı, herhangi bir blog yazısındaki genel ifadeden daha güvenilir bir karar kaynağıdır.

Xcode 27'ye geçiş kontrol listesi

Aşağıdaki tablo, publish tarihi itibarıyla (beta dönemi) bilinen değişiklikleri ve önerilen aksiyonu özetliyor:

Adım
Ne değişti
Yapılacak
@State init'leri
Deklarasyon + init'te çifte atama artık kırılıyor
Değeri tek yerde tanımla (yalnızca init'te)
AsyncImage
Varsayılan olarak standart HTTP cache uyguluyor
Kod değişikliği gerekmiyor, sunucu cache header'larını kontrol et
ContentBuilder
Builder artık View'a kısıtlı değil
Ambiguous hatalarda trailing closure formuna geç
Generic çıkarımı
@State'in generic argüman çıkarımı daha az esnek
Çıkarım hatası verene açık tip anotasyonu yaz
Coding assistant
Xcode 27, yeni SwiftUI API'lerini benimsetmek için agent skills seti getiriyor
Yeni API adaptasyonunda coding assistant'taki skill setini dene

SwiftUI Navigation Sistemi ve SwiftUI NavigationStack Deep Dive yazılarımızdaki örnekler de bu sürümle birlikte derlenmeye devam ediyor; @State kullanan navigation state'lerini geçiş öncesi taramanı öneririz.

AsyncImage'daki değişiklik listede küçük görünse de, üretim uygulamalarında en az gürültü çıkaracak olanı bu — çünkü hiçbir kod değişikliği gerektirmiyor. WWDC26 rehberi, AsyncImage'ın artık standart HTTP cache davranışını uyguladığını ve sunucunun gönderdiği cache header'larına saygı gösterdiğini belirtiyor. Bu, aynı görseli tekrar tekrar indiren eski davranışın yerini, tarayıcı benzeri bir önbellekleme mantığının aldığı anlamına geliyor. Tek yapman gereken, backend'inin görsel yanıtlarında doğru Cache-Control başlıklarını gönderdiğinden emin olmak — aksi halde bu iyileşmeden faydalanamazsın.

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

Okuyucu Ödülü

Xcode 27'ye geçmeden önce projende hızlıca gözden geçirebileceğin bir öz-denetim listesi hazırladık. Aşağıdaki maddeleri sırayla işaretleyerek geçiş öncesi riskli noktaları önceden yakalayabilirsin.

SSS

SwiftUI'da @State neden macro oldu?

Eski property-wrapper implementasyonu, @State private var model = Model() gibi bir başlangıç değerini view struct'ı her yeniden oluşturulduğunda tekrar hesaplıyordu — SwiftUI fazladan oluşan örnekleri sonradan atsa da, Model() init'i yine de çalışıyordu. Xcode 27, @State'i Swift macro olarak yeniden yazarak başlangıç değerinin yalnızca bir kez, lazy şekilde değerlendirilmesini sağlıyor.

'@State atanamıyor' derleme hatası nasıl çözülür?

Bir @State property'sine hem deklarasyon yerinde başlangıç değeri verip hem de init içinde tekrar atama yapma — bu "used before being initialized" hatası verir. Doğru çözüm, başlangıç değerini deklarasyondan kaldırıp yalnızca init içinde tanımlamak. Ek nüans: hata yalnızca view'da ikinci bir stored property varken çıkıyor ve mesaj @State'i değil, o diğer property'yi adlandırıyor.

ContentBuilder nedir, ViewBuilder'dan farkı ne?

ContentBuilder, Apple'ın ViewBuilder, ToolbarContentBuilder, CommandsBuilder gibi tip-özel result builder'larını tek bir birleşik mekanizma altında topladığı yapı. Farkı, içeriğini artık View protokolüne uymaya zorlamaması — bunun bedeli bazı ifadelerin (örneğin .overlay(someShapeStyle)) artık "ambiguous" hatası vermesi; trailing closure formuna geçmek bu belirsizliği çözüyor.

iOS 27'de build süresi neden kısaldı?

WWDC26 SwiftUI rehberi, ViewBuilder'ın ContentBuilder olarak açığa çıkmasıyla Xcode 27'de build sürelerinin önemli ölçüde iyileştiğini belirtiyor. Bu ifade nitel; kamuya açık, tekrarlanabilir bir yüzde rakamı birincil kaynaklarda paylaşılmıyor. Kendi projendeki gerçek kazancı görmek için yukarıdaki "build süresini nasıl ölçersin" bölümündeki adımları izleyebilirsin.

Güncelleme (Eylül 2026)

Xcode 27.0 GA, 14 Eylül 2026'da yayınlandı (build 27A266a). GA toolchain'i test edildiğinde, beta döneminde "iki ayrı kırık pattern" sanılan durumun aslında tek, sıra-bağımlı bir davranış olduğu görüldü: declaration'da başlangıç değeri olan bir @State property'si, init içinde diğer stored property'lerden önce set edilirse hata veriyor; sonra set edilirse aynı dosya derleniyor — ama Apple'ın tarif ettiği gibi @State ataması sessizce atılıyor. Yani sıra değiştirmek yanlış çözüm; doğru çözüm başlangıç değerini kaldırmaktır. Extension'dan gelen memberwise init çağrısı ise GA'da değişmeden derlendi. Bu bulgu, macro'nun -Xfrontend -dump-macro-expansions çıktısında görülebilen init-accessor mekanizmasıyla doğrulandı.

Senaryo
Beta (Haziran 2026)
GA (Eylül 2026, Xcode 27.0)
Declaration'da initial value + init'te tekrar atama
"used before being initialized" hatası veriyor
Hâlâ hata veriyor, ama sıraya bağımlı
Extension'dan memberwise init çağrısı
Kırık pattern olarak listeleniyordu
GA'da değişmeden derleniyor
Property atama sırası (örn. page önce, title sonra)
Belgelenmemiş bir ayrıntıydı
Sıra değişince hata kayboluyor, netleşti

Bu düzeltmeyi doğrulayan bir başka gözlem de blakecrosley'in kendi saha denetiminde geldi: yazar dört canlı uygulamasını tarayıp 267 @State deklarasyonunu tek tek incelemiş, bunların 201'i deklarasyon yerinde başlangıç değeri taşıyormuş. Sonuç: sıfır gerçek kırılma, yalnızca bir "az kalsın" vakası. Bu, beta döneminde beklenen kırılma yaygınlığının pratikte öngörülenden daha sınırlı çıktığını gösteren, tek kaynaklı ama somut bir saha verisi — genel bir istatistik olarak değil, bu belirli denetimin sonucu olarak okunmalı.

Sonuç

@State'in macro'ya dönüşmesi, Xcode 27'ye geçen her SwiftUI geliştiricisinin karşılaşacağı en somut kırıcı değişiklik; ama düzeltmesi tek satırlık: başlangıç değerini deklarasyon yerine değil, yalnızca init içine koy. ViewBuilder'ın ContentBuilder olarak açığa çıkması ise daha sinsi bir etki yaratıyor — bazı çağrılarda ambiguous hatalarına yol açıyor, ama trailing closure formu çoğu durumda çözüyor. Kırılmanın gerçekten çıkması için view'da ikinci bir stored property ve belirli bir atama sırası gerekiyor; bu yüzden geçiş öncesi varsayımla değil, derleyici hatasıyla doğrula.

Konuyu derinleştirmek istersen SwiftUI Property Wrapper'ları Deep Dive yazımızda @State'in eski property-wrapper dönemini, Swift Macros Deep Dive yazımızda derleme-zamanı kod üretiminin genel mantığını, SwiftUI'da Performance Optimizasyonu yazımızda ise view yeniden çizimlerini azaltma tekniklerini bulabilirsin. Navigation state'lerini bu değişiklikten etkilenen ekranlarda kontrol etmek için SwiftUI Navigation Sistemi yazımıza da göz atabilirsin.

Kaynaklar

Etiketler

#SwiftUI#Xcode 27#iOS 27#Swift Macro#ContentBuilder#Build Performance
Muhittin Çamdalı

Muhittin Çamdalı

Lead Mobile Engineer

12+ yıllık deneyime sahip Lead Mobile Engineer. Swift, SwiftUI, Kotlin ve Flutter ile iOS, Android ve cross-platform mimarilerde uzman. Performanslı ve kullanıcı dostu mobil uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

İlgili İçerik