SwiftUI ekranlarında HTTP cache, ETag doğrulaması ve çevrimdışı veri akışını ölçülebilir biçimde kurun. Bu swift eğitimi rehberi, URLSession, actor tabanlı depo ve Instruments ile gerçek ağ maliyetini ele alır.
SwiftUI Eğitiminde URLSession Cache, ETag ve Offline Veri Tasarımı
SwiftUI eğitiminde HTTP cache politikasını endpoint bazında kurmak
Birçok istemci, tüm istekleri .reloadIgnoringLocalCacheData ile göndererek ETag, Cache-Control ve URLCache davranışını fiilen devre dışı bırakır. Bunun sonucunda aynı liste ekranına her dönüşte yeniden TLS bağlantısı, istek gövdesi ve JSON parse maliyeti oluşur. Sunucu yanıtı Cache-Control: private, max-age=60 ve ETag dönüyorsa, GET isteğini varsayılan .useProtocolCachePolicy ile bırakın. Bu politika, taze bir disk veya bellek girdisini ağ yerine URLCache'ten verir; girdinin süresi dolduğunda ise koşullu doğrulama için ağ katmanına geçer.
final class APIClient {
private let session: URLSession
init() {
let memory = 20 * 1024 * 1024
let disk = 100 * 1024 * 1024
let cache = URLCache(memoryCapacity: memory, diskCapacity: disk)
let configuration = URLSessionConfiguration.default
configuration.urlCache = cache
configuration.requestCachePolicy = .useProtocolCachePolicy
configuration.waitsForConnectivity = true
self.session = URLSession(configuration: configuration)
}
func products() async throws -> [Product] {
var request = URLRequest(url: URL(string: "https://api.example.com/products")!)
request.cachePolicy = .useProtocolCachePolicy
let (data, response) = try await session.data(for: request)
guard let http = response as? HTTPURLResponse,
(200...299).contains(http.statusCode) else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode([Product].self, from: data)
}
}Xcode Network Report veya Instruments içindeki Network şablonunda aynı ekranı iki kez açarak ölçüm yapın. Önce mevcut zorlayıcı cache politikasıyla ikinci açılıştaki request count, transferred bytes ve request duration değerlerini kaydedin. Ardından yukarıdaki yapılandırmayla aynı senaryoyu çalıştırın. İkinci açılışta 200 yerine cache hit ya da doğrulama sonrası 304 görmek gerekir. 304 yanıtının gövdesi yoktur; URLSession, daha önce sakladığı gövdeyi birleştirerek çağırana veri verir. Bu nedenle 304 alan uygulama kodunun boş Data decode etmeye çalışması, yaygın ama hatalı bir özel URLProtocol veya manuel ETag implementasyonu belirtisidir.
ios mvvm mimarisi içinde ETag ve stale veri deposu
HTTP cache tek başına ürün gereksinimini karşılamaz: kullanıcı uygulamayı uçak modunda açtığında ya da sunucu 500 döndürdüğünde son başarılı domain verisini göstermek isteyebilirsiniz. ios mvvm mimarisi içinde ViewModel'in URLCache, UserDefaults ve ağ hatalarını doğrudan bilmesi yerine, bir repository actor'ü iki kaynağı birleştirsin. Actor, aynı endpoint için eşzamanlı yenileme isteklerinin disk yazımını yarışa sokmasını engeller; ViewModel yalnızca LoadState üzerinden ekrana karar verir.
actor ProductRepository {
private let client: APIClient
private let store: ProductStore
init(client: APIClient, store: ProductStore) {
self.client = client
self.store = store
}
func load() async -> ProductSnapshot {
let cached = try? await store.read()
do {
let products = try await client.products()
let snapshot = ProductSnapshot(products: products, fetchedAt: .now)
try await store.write(snapshot)
return snapshot
} catch {
if let cached {
return cached.markedStale(reason: error.localizedDescription)
}
throw error
}
}
}
@MainActor
final class ProductListViewModel: ObservableObject {
@Published private(set) var state = LoadState.idle
private let repository: ProductRepository
func refresh() async {
state = .loading
do { state = .loaded(try await repository.load()) }
catch { state = .failed(error.localizedDescription) }
}
}Kalıcı snapshot için Application Support altına atomik dosya yazın; Documents klasörü kullanıcı verisi içindir, cache niteliğindeki yeniden indirilebilir veri için doğru varsayılan değildir. Dosyayı önce geçici URL'ye yazıp FileManager.replaceItemAt ile değiştirin. Doğrudan hedef dosyaya yazmak, uygulama yazım ortasında sonlandırılırsa yarım JSON bırakabilir. Şema değişiminde decoding hatasını ağ hatası gibi stale gösterme hatasına düşmeyin: `DecodingError` için dosyayı silip telemetry olayına model sürümünü ekleyin.
Swift kursu projelerinde cache anahtarları ve Vary tuzağı
URLCache anahtarı yalnızca URL'den ibaretmiş gibi düşünülmemelidir. Sunucu `Vary: Accept-Language` veya `Vary: Authorization` gönderiyorsa aynı URL'nin dili ya da kullanıcı bağlamı değişir. Kişiselleştirilmiş `GET /me` yanıtlarını shared cache'e koymak, çıkış yapan kullanıcının verisinin yeni oturumda görünmesine yol açabilir. Token yenileme ve logout anında yalnızca cookie silmek yerine ilgili URLCache girdilerini de temizleyin.
func clearPrivateResponses() {
guard let url = URL(string: "https://api.example.com/me") else { return }
let request = URLRequest(url: url)
URLCache.shared.removeCachedResponse(for: request)
}
func makeLocalizedRequest(path: String, locale: Locale) -> URLRequest {
var request = URLRequest(url: URL(string: "https://api.example.com/\(path)")!)
request.setValue(locale.identifier, forHTTPHeaderField: "Accept-Language")
request.cachePolicy = .useProtocolCachePolicy
return request
}Sunucu ekibinden kişisel veriler için `Cache-Control: no-store` isteyin. `no-cache` veriyi saklamayı yasaklamaz, her yeniden kullanımda doğrulamayı zorunlu kılar; `no-store` ise saklanmamasını hedefler. Bu ayrım, iphone uygulama geliştirme sırasında özellikle hesap ekranları ve tek kullanımlık imzalı URL'lerde önemlidir. Charles Proxy veya Proxyman ile yanıt başlıklarını inceleyin; yalnızca istemci log'una bakmak, CDN'in eklediği Cache-Control ve Vary başlıklarını gözden kaçırabilir.
Xcode eğitimi için cache etkisini Instruments ile profil etmek
Cache değişikliğini kabul etmeden önce ölçüm senaryosunu sabitleyin: temiz kurulum, ilk liste açılışı, uygulamayı arka plana alıp geri dönüş ve manuel yenileme. Xcode'da Product > Profile ile Instruments açın, Network şablonunda `api.example.com` host'una filtre uygulayın. Her senaryoda request sayısı, alınan byte, toplam ağ süresi ve HTTP durum kodlarını CSV olarak dışa aktarın. Önce `.reloadIgnoringLocalCacheData`, sonra `.useProtocolCachePolicy` ile aynı test cihazında karşılaştırın; Wi-Fi ve hücresel ağ sonuçlarını aynı tabloya karıştırmayın.
Zaman çizelgesinde 304 sayısının artması tek başına başarı değildir. ETag doğrulaması yine bir ağ gidiş-dönüşü gerektirir. `max-age` değeri ürünün kabul ettiği bayatlık penceresinden kısa ise kullanıcı her dönüşte 304 bekler. Örneğin katalog 10 dakika gecikmeyi tolere ediyorsa sunucu tarafında `max-age=600` seçimi, 60 saniyelik değere göre daha az doğrulama üretir. Bu kararın karşılığı, ekranda snapshot zamanını göstererek kullanıcının ve destek ekibinin verinin ne kadar eski olduğunu ayırt edebilmesidir.
Bu xcode eğitimi yaklaşımında Instruments'a ek olarak `URLSessionTaskMetrics` kaydedin. `resourceFetchType` değeri `.localCache` olduğunda çağrının yerel cache'ten geldiğini, `.networkLoad` olduğunda ağ kullanıldığını gösterir. Metrikleri endpoint, ekran ve uygulama build kimliğiyle os.Logger üzerinden toplayın; yalnızca ortalama yerine p95 `taskInterval.duration` değerini inceleyin. Seyrek görülen DNS veya bağlantı kurulumu gecikmeleri ortalamada gizlenir.
ios eğitimi kapsamında offline ekranın yayın öncesi test matrisi
Offline davranışı simülatörde yalnızca Mac'in Wi-Fi bağlantısını kapatarak test etmeyin; gerçek cihazda Ayarlar'dan uygulamanın hücresel verisini kapatın ve Network Link Conditioner ile yüksek gecikme, %5 paket kaybı ve düşük bant genişliği profilleri deneyin. UI testinde fırlatma argümanı ile stub URLProtocol seçerek deterministik 200, 304, 500 ve bağlantı yok senaryoları üretin. Böylece ağ hatası altında stale snapshot gösterimi sürümden sürüme tekrarlanabilir kalır.
final class ProductOfflineUITests: XCTestCase {
func testShowsCachedProductsWhenNetworkFails() {
let app = XCUIApplication()
app.launchArguments += ["-useStubNetwork", "-seedProductSnapshot"]
app.launchEnvironment["STUB_PRODUCTS_STATUS"] = "offline"
app.launch()
XCTAssertTrue(app.staticTexts["Cached products"].waitForExistence(timeout: 2))
XCTAssertTrue(app.staticTexts["Updated 10 min ago"].exists)
XCTAssertFalse(app.staticTexts["Retry"].exists)
}
}app store yayınlama öncesinde inceleme notlarına ağ gerektiren hesap özelliklerini ve offline durumda gösterilen davranışı yazın. Ayrıca Privacy Manifest ile kullanılan third-party SDK'ların topladığı tanımlayıcıları denetleyin; cache'e erişim token'ı veya hassas profil alanı yazmayın. ios kursu veya swiftui eğitimi laboratuvarında bu testi, uygulama yeniden başlatıldıktan sonra disk snapshot'ının gerçekten okunup okunmadığını doğrulayacak şekilde genişletin. `URLCache` işletim sistemi tarafından temizlenebilir, bu yüzden offline ürün vaadini yalnızca ona dayandırmak doğru değildir.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Sık Sorulan Sorular
SwiftUI eğitiminde URLCache ile ETag birlikte nasıl test edilir?
Xcode Product > Profile üzerinden Instruments Network şablonunu açın, aynı GET ekranını iki kez gezinin ve ikinci isteğin durum kodu ile transferred bytes değerini kaydedin. Taze `max-age` penceresinde yerel cache hit, süre dolduktan sonra ETag kullanılıyorsa 304 bekleyin. Charles Proxy ile `Cache-Control`, `ETag` ve `If-None-Match` başlıklarını ayrıca doğrulayın.
ios mvvm mimarisi içinde offline veri ViewModel'de mi tutulmalı?
Hayır. ViewModel `LoadState` ve kullanıcı eylemlerini yönetmeli, disk okuma-yazma ile ağ fallback kararını actor tabanlı repository vermelidir. Repository'nin `load()` metodunu sahte APIClient ve geçici ProductStore ile unit test edin; 500 durumunda stale snapshot, ilk açılışta ise hata üretmesini ayrı testlerde doğrulayın.
swift kursu projesinde URLSession reloadIgnoringLocalCacheData ne zaman kullanılmalı?
Bu politikayı yalnızca kullanıcının açıkça istediği yenileme gibi durumlarda ve sunucu sözleşmesi gerektiriyorsa kullanın. Normal ekran açılışında bu ayar URLCache'i atlar, koşullu ETag doğrulamasını da beklediğiniz gibi kullanmayabilir ve her seferinde ağ yükü oluşturur. Pull-to-refresh için bile önce endpoint'in Cache-Control ve ETag davranışını Proxyman veya Network Instruments ile ölçün.
iphone uygulama geliştirme sürecinde URLCache kalıcı offline depo sayılır mı?
Hayır. URLCache'in disk girdileri işletim sistemi tarafından alan gerektiğinde temizlenebilir ve saklama ömrü HTTP başlıklarına bağlıdır. Uygulamanın offline açılması bir gereksinimse, versioned Codable snapshot'ı Application Support altında atomik biçimde saklayın; URLCache'i ise HTTP yanıt optimizasyonu olarak değerlendirin.
AI / LLM Discovery
Bu makale Opendart Akademi iOS / Swift eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.


