Actor, dil düzeyinde veri yarışı sorununu çözen Swift 5.5+'ta tanıtılan bir türdür. Manuel kilitlerin ve DispatchQueue kuyruklarının aksine, bir actor otomatik olarak durumunu yalıtır ve ona erişimi senkronize eder. Bu, iki iş parçacığının aynı anda bir actor türünün aynı özelliğini değiştiremeyeceği ve geliştiricinin ek çabası olmadan yarış koşullarını ortadan kaldırdığı anlamına gelir. Mekanizma, derleyicinin actor özelliklerine ve yöntemlerine erişimi izlediği actor yalıtımı kavramına dayanır. Apple, 2025'e göre, actor modeli Swift'in eşzamanlılık sisteminin temel bir parçasıdır.
Önemli Noktalar
Actor, bir sınıfa benzer ancak veri yarışlarına karşı otomatik korumaya sahip bir referans türüdür. Swift 5.5'te async/await ve Task ile birlikte eşzamanlılık sisteminin bir parçası olarak tanıtılmıştır. Bir actor, değişebilir durumunun açık senkronizasyon olmadan farklı iş parçacıklarından asla aynı anda okunmayacağını veya yazılmayacağını garanti eder.
Bir actor bildirmek için, actor anahtar sözcüğü ve ardından üyeleriyle birlikte süslü parantezler kullanılır. Sözdizimsel olarak, bir actor bir sınıfa benzer, ancak davranışı kökten farklıdır.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
self.balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
Derleyici, tüm actor özelliklerini ve yöntemlerini otomatik olarak yalıtarak yalnızca actor bağlamı içinde erişilebilir olmalarını sağlar. Actor'ün dışından balance'a erişmeye çalışırken, çağrı async olarak işaretlenmemişse derleyici bir hata üretecektir.
Veri yalıtımı, bir actor'ün temel kavramıdır. Bir actor, actor yürütücü mekanizması aracılığıyla durumuna karşılıklı olarak özel erişimi garanti eder. Her actor'ün, yalıtılmış üyelerine tüm erişimleri sırayla işleyen kendi yürütücüsü vardır.
Actor'ün dışındaki kod onun yöntemini çağırdığında, çağrı actor yürütücü kuyruğuna yerleştirilir. Actor, aynı anda yalnızca bir görev yürüterek yarışların olmamasını garanti eder. İki iş parçacığı aynı anda deposit çağırırsa, ikinci çağrı birincinin tamamlanmasını bekler.
let account = BankAccount(initialBalance: 1000.0)
// Eşzamansız çağrı — actor dışından gerekli
await account.deposit(amount: 500.0)
let currentBalance = await account.getBalance()
Actor yöntemine yapılan her çağrı await gerektirir çünkü actor başka bir görevle meşgul olabilir. Bu bir hata değil, yarışları önleyen bilinçli bir tasarımdır. Swift, actor özelliklerinin getter ve setter'larını örtük olarak async yapar, bu nedenle bir özelliği okumak da await gerektirir.
Actor ve sınıfın her ikisi de referans türleridir, ancak çok iş parçacıklı bir ortamda davranışları büyük ölçüde farklılık gösterir. Bir sınıf, yarışlara karşı hiçbir otomatik koruma sağlamazken, bir actor bunu tür sistemi aracılığıyla derleyici düzeyinde gömer.
| Özellik | Actor | Sınıf |
|---|---|---|
| Yarış koruması | Otomatik, derleyici düzeyinde | Manuel senkronizasyon gerektirir |
| Özellik erişimi | Yalnızca dışarıdan await ile | Doğrudan, senkronizasyon olmadan |
| Kalıtım | Yalnızca diğer actor'lerden | Standart sınıf tabanlı |
| Protokol uygunluğu | Protokollere uygun olabilir | Standart |
| Performans | Yalıtımla düşük ek yük | Senkronizasyon olmadan daha hızlı |
Bir actor yalnızca başka bir actor'den miras alabilir ve bir sınıftan miras alamaz. Bu kasıtlıdır çünkü bir sınıf actor yalıtım mekanizmasından yoksundur ve türleri karıştırmak güvenlik garantilerini bozar.
actor SavingsAccount: BankAccount {
func applyInterest(rate: Double) {
let interest = balance * rate
balance += interest
}
}
Eşzamansız çağrılar, harici koddan bir actor ile etkileşim kurma mekanizmasıdır. Bir actor durumunu yalıttığından, dışarıdan üyelerine herhangi bir erişim await gerektirir. Bu, Swift'in çağıran kodun iş parçacığını bloke etmemesini ve actor'ün diğer istekleri işleyebilmesini garanti etmesini sağlar.
Bildirilen actor türlerine ek olarak, Swift genel actor'leri — @MainActor özniteliğini destekler. Bu, sınıfları, özellikleri veya yöntemleri ana iş parçacığında yürütülebilir olarak işaretler. Bu, iOS uygulamalarındaki UI kodu için özellikle kullanışlıdır.
@MainActor
class ViewModel: ObservableObject {
@Published var title: String = ""
func updateTitle() {
// Bu kodun ana iş parçacığında çalışması garanti edilir
title = "New Title"
}
}
@MainActor kullanımı, manuel olarak DispatchQueue.main.async çağırma ihtiyacını ortadan kaldırır ve kodu daha temiz ve güvenli hale getirir. Derleyici, ana iş parçacığına geçişin doğru şekilde gerçekleşmesini sağlar.
Nonisolated, bir actor'ün bir yöntemini veya hesaplanmış özelliğini yalıtılmamış olarak işaretlemeye izin veren bir anahtar sözcüktür. Bu tür üyeler, actor'ün yalıtılmış durumuna erişemez, ancak actor'ün dışından await olmadan çağrılabilir.
Nonisolated yöntemler, actor'ün değişebilir durumuna bağlı olmayan hesaplamalar için kullanışlıdır. Örneğin, formatBalance yöntemi doğrudan balance'a erişmez, yalnızca iletilen değeri biçimlendirir — böyle bir yöntemi nonisolated yapmak güvenlidir.
actor BankAccount {
private var balance: Double = 0
nonisolated func formatBalance(amount: Double) -> String {
return "$\(amount)"
}
}
Nonisolated üyeler eşzamanlı olarak yürütülür ve await gerektirmez. Ancak, actor tarafından yalıtılmış özellikleri doğrudan okuyamazlar. Bir nonisolated yöntemin actor'den bir değere ihtiyacı varsa, parametre olarak iletilmesi gerekir.
Reentrancy, eşzamansız bir çağrıyı beklerken bir actor'e yeniden girişe izin veren bir mekanizmadır. Reentrancy olmadan, bir actor'ün yöntemlerinden biri, sırayla ilkini bekleyen bir başkasını bekleseydi, actor sonsuza kadar kilitlenebilirdi.
Actor'ün içindeki kod await yürüttüğünde, actor geçerli görevi askıya alır ve sıradaki başka bir görevi işleyebilir. Await tamamlandıktan sonra görev devam eder. Bu, kilitlenmeleri önler ancak dikkat gerektirir: await noktaları arasında actor'ün durumu değişebilir.
actor DataProcessor {
var cache: [Int: String] = [:]
func process(id: Int) async -> String {
if let cached = cache[id] {
return cached
}
// await — yeniden giriş noktası
let result = await fetchData(id: id)
// Await'ten sonra önbellek değişmiş olabilir — tekrar kontrol edin
cache[id] = result
return result
}
}
Geliştiriciler, yeniden girişi hesaba katmalı ve await noktalarından sonra actor'ün durumunu kontrol etmelidir. Tipik bir hata, actor yalıtımının eşzamansız askıya alma noktaları boyunca devam ettiğini varsaymaktır. Pratikte, await ile sonraki ifade arasında durum beklenenden farklı olabilir.
Sıkça Sorulan Sorular
Actor, durumunu otomatik olarak veri yarışlarından yalıtır ve harici erişim için await gerektirir. Bir sınıf bu tür bir koruma sağlamaz — geliştirici, kilitler veya kuyruklar aracılığıyla senkronizasyondan sorumludur. Bir actor yalnızca actor'den miras alır, bir sınıf bir sınıftan miras alır.
Evet, bir actor başka bir actor'den miras alabilir. Alt sınıf, ebeveynin tüm yalıtılmış özelliklerini ve yöntemlerini alır. Bir actor, bir sınıftan miras alamaz çünkü sınıflar derleyici düzeyinde actor yalıtım mekanizmasına sahip değildir.
actor-isolated bağlam, actor'ün değişebilir durumuna doğrudan erişime izin verilen bir kod alanıdır. Yalıtılmış olarak işaretlenmiş (varsayılan olarak) actor yöntemlerinin içinde, await olmadan özellikler okunabilir ve yazılabilir. Derleyici yalıtım sınırlarını kontrol eder.
Actor'den veriler, Sendable türleri döndüren async yöntemler veya parametre olarak değerleri kabul eden nonisolated yöntemler aracılığıyla aktarılır. Ayrıca, Sendable bir yapı olarak actor'ün durumunun bir anlık görüntüsünü döndüren bir async özelliği oluşturulabilir.
Evet, bir actor protokollere uygun olabilir. Bir protokol yalıtılmış gereksinimler (actor-isolated) içeriyorsa, bunlar otomatik olarak actor tarafından yalıtılmış hale gelir. Protokollerdeki eşzamansız yöntemler için, isolated işaretçisi kullanılarak belirli bir actor'de çağrılmaları gerektiği belirtilebilir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun