Automatic Reference Counting (ARC) — Swift və Objective-C-də yaddaşı idarəetmə sistemidir, hər bir obyektə olan referansların sayını avtomatik hesablayır və sayı sıfıra çatdıqda onu azad edir. Apple Swift Documentation, 2026-ya görə, ARC kompilyatora daxil edilib və kompilyasiya mərhələsində işləyir, lazımi yerlərdə retain/release çağırışlarını yerləşdirir. Garbage Collection-dan fərqli olaraq, ARC ayrıca toplayıcı ipi tələb etmir və tətbiqin icrası zamanı fasilələr yaratmır.
Əsas məqamlar
ARC (Automatic Reference Counting) — Apple tərəfindən Xcode 4.2-də (2011) Objective-C üçün təqdim edilmiş və Swift tərəfindən miras alınmış kompilyator yaddaş idarəetmə mexanizmidir. Manual Retain-Release (MRR)-dən fərqli olaraq, ARC retain, release və autorelease çağırışlarını tam avtomatlaşdırır, onları kompilyasiya mərhələsində proqramçının iştirakı olmadan yerləşdirir.
ARC garbage collector deyil. Bu, dinamik kod yerləşdirmə ilə statik analizdir: kompilyator obyektlərin ömür müddətini təhlil edir və obyektlərin yaradıldığı, kopyalandığı və ya görünüş dairəsindən çıxdığı nöqtələrdə retain/release yerləşdirir. Nəticə — deterministik yaddaş boşaldılması: obyekt ona istinadlar dayandıqda dəqiq həmin anda, gecikmələr və fasilələr olmadan silinir.
WWDC 2011 Session 323-yə görə, MRR-dən ARC-yə keçid Apple tətbiqlərində yaddaşla bağlı crash-buqların sayını 70% azaldıb. Proqramçılar əl ilə retain/release balanslaşdırmağı dayandırdılar, bu da bütöv bir sınıf sızıntı və double-free səhvlərini aradan qaldırdı.
Yaddaşdakı hər bir obyektin referans sayı (retain count) var. Obyekt yaradıldıqda say 1 olaraq təyin edilir. Yeni strong-referans obyektə istinad etdikdə say artır (retain). Strong-referans yox olduqda say azalır (release). Sıfıra çatdıqda obyekt dərhal dealokasiya edilir.
Swift kompilyatoru retain/release-i hər təyinata deyil — optimallaşdırma üçün statik analizdən istifadə edir. Məsələn, əgər obyekt ötürüldükdən sonra istifadə edilməyəcəksə, kompilyator artıq release/retain-i buraxa bilər. Bu optimallaşdırmaya ARC Optimisation deyilir.
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) işə salındı (retain count: 1)")
}
deinit {
print("\(name) dealokasiya edildi")
}
}
func testARC() {
let p = Person(name: "Alice") // retain count = 1
let q = p // retain count = 2
// q görünüş dairəsindən çıxır
// retain count = 1
// p görünüş dairəsindən çıxır
// retain count = 0 → deinit
}
Bu nümunədə ARC-nin sayı necə idarə etdiyi görünür: q = p təyin edildikdə say artır, q görünüş dairəsindən çıxdıqda azalır. Son strong-referans yox olduqda deinicializator dərhal çağırılır. Heç bir garbage collector gözləmir — yaddaş dərhal azad edilir.
ARC və Garbage Collection eyni vəzifəni — avtomatik yaddaş idarəetməni — həll edir, lakin prinsipial olaraq fərqli yanaşmalarla. Onlar arasındakı seçim dilin arxitekturasını müəyyənləşdirir: Swift (ARC) vs Java/Go (GC). Əsas fərqləri nəzərdən keçirək.
| Xüsusiyyət | ARC (Swift/ObjC) | GC (Java/Go) |
|---|---|---|
| Boşaltma anı | Deterministik: say sıfırlandıqda dərhal | Qeyri-deterministik: növbəti yığımda |
| İcra fasilələri | Yoxdur (kompilyasiya mərhələsində retain/release əlavələri) | Stop-The-World fasilələri var (2–200 ms) |
| Əlavə yük | Hər referansda sayın artırılması/azaldılması | Obyekt qrafının gəzilməsi, işaretləmə, təmizləmə |
| Problemlər | Retain Cycle (əl ilə həll) | Heap fraqmentasiyası, unudulmuş referanslarda sızıntılar |
| Əlavə ip | Tələb olunmur | Garbage collector ipi tələb olunur |
Əsas kompromis: ARC obyektlərin proqnozlaşdırıla bilən ömür müddətini və sıfır fasilələri təmin edir, lakin proqramçıdan retain cycle anlayışı və düzgün weak/unowned seçimi tələb edir. GC bu narahatlıqlardan azad edir, lakin qeyri-deterministik fasilələr və əlavə ip bahasına.
ARC üç növ referans kvalifikatoru təyin edir, onların hər biri sayı və obyektin həyat dövrünü fərqli şəkildə təsir edir. Kvalifikatorun düzgün seçimi Swift-də təhlükəsiz yaddaş işinin əsasıdır.
Strong — standart kvalifikator. Hər bir strong-referans obyektin retain count-nu 1 artırır. Heç olmasa bir strong-referans mövcud olduğu müddətdə obyekt yaşayır. Swift-də sinif xüsusiyyətləri və lokal dəyişənlər standart olaraq strong-dur. Strong-referanslar sahiblik münasibəti yaradır: A obyekti B obyektinə sahibdir.
Weak — retain count-u artırmayan referansdır. Obyekt weak-referans ona istinad etsə belə dealokasiya edilə bilər. Dealokasiyadan sonra weak-referans avtomatik olaraq nil olaraq təyin edilir. Weak-referanslar həmişə isteğçi tiplə (?) var kimi bəyan edilir. Onlar retain cycle-ı qırmaq üçün, xüsusilə delegate nümunəsində istifadə olunur.
Unowned — weak kimi retain count-u artırmayan sahib olmayan referansdır. Lakin unowned-referans dealokasiyadan sonra nil olaraq təyin edilmir — azad edilmiş obyektə müraciət crash-a səbəb olur. Unowned obyektin referans edən obyektdən azı qədər yaşayacağı təmin edildikdə istifadə olunur. Tipik ssenari — qapanmalar (closures) və təmin edilmiş ömür müddəti ilə valideyn-uşaq münasibətləri.
class Customer {
let name: String
var card: CreditCard? // strong
init(name: String) { self.name = name }
deinit { print("\(name) dealokasiya edildi") }
}
class CreditCard {
let number: String
unowned let customer: Customer // unowned — sahib deyil
init(number: String, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Kart \(number) dealokasiya edildi") }
}
var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer və CreditCard hər ikisi azad edildi — retain cycle yoxdur
Burada CreditCard Customer-ə unowned-referansdan istifadə edir. Customer karta sahibdir (strong), karta isə müştəriyə sahib deyil (unowned). Customer nil olduqda hər iki obyekt azad edilir — retain cycle yaranmır. Əgər card.customer strong olsaydı, dövrü azad olmağı bloklayardı.
Avtomatlaşdırmaya baxmayaraq, ARC panacea deyil. Proqramçılar yaddaş idarəetmə mexanizmini anlamağı tələb edən bir neçə tipik problemlə qarşılaşırlar.
Swift-də qapanmalar (closures) xarici dəyişənləri strong-referansla tutur. Əgər qapanma sinifin xüsusiyyətinə təyin edilirsə və self-i tutursa — retain cycle yaranır: sinif qapanmanı, qapanma self-i saxlayır. Həll — weak və ya unowned ilə capture list.
class NetworkManager {
var completionHandler: ((Data?) -> Void)?
var data: Data?
func fetchData() {
completionHandler = { [weak self] result in
guard let self else { return }
self.data = result
self.processResult()
}
}
func processResult() { }
}
Capture list [weak self] qapanma daxilində self-ə weak-referans yaradır. Bu potensial retain cycle-ı qırır. Guard let self kodu icra etməzdən əvvəl obyektin canlı olduğunu təmin edir. weak self — Swift-də asinxron qapanmalar üçün standart təcrübədir.
Retain/release yüngül əməliyyatlar olsa da, isti dövrülərdə tez-tez say artırılması/azaldılması əlavə yük yaradır. Swift 5.9+-da kompilyator optimallaşdırma istifadə edir, burada analizator təhlükəsizliyi sübut edərsə, artıq retain/release-lər silinir. Bununla belə, Objective-C-də retain/release saniyədə milyonlarla çağırışlı yüksək yüklü ssenarilərdə hələ də darboğaz ola bilər.
Autorelease Pool — Objective-C və Swift-in bəzi ssenarilərində istifadə olunan gecikdirilmiş release mexanizmidir. Obyektlər hovuza yerləşdirilir və hovuz boşaldıldıqda release alır. Çox sayda müvəqqəti obyekti olan dövrülərdə (məsələn, JSON parse etmə) öz autoreleasepool yaratmaq operativ yaddaşın pik istehlakını azaldır.
Tez-tez verilən suallar
Əl ilə idarəetmədə (MRR) proqramçı açıq şəkildə retain, release və autorelease çağırırdı. ARC bu çağırışları kompilyasiya mərhələsində avtomatik yerləşdirir, double-free riskini, unudulmuş release səbəbindən sızıntıları və retain/release balanslaşdırma səhvlərini aradan qaldırır.
ARC yalnız Objective-C obyektləri və Swift class-larını idarə edir. C/C++ strukturları və göstəriciləri üçün ARC tətbiq edilmir — bu obyektlər əl ilə və ya C++ ağıllı göstəriciləri (shared_ptr, unique_ptr) vasitəsilə idarə olunur. Core Foundation obyektləri (CFString, CGColor) də ARC-yə daxil deyil.
weak — obyekt referans edəndən daha tez dealokasiya edilə bildikdə (delegatlar, asinxron qapanmalar). unowned — obyektin referans edəndən az olmayaraq yaşayacağı təmin edildikdə (valideyn-uşaq, uşaq valideyn olmadan mövcud ola bilməz). Əgər əminsinizsə — weak seçin.
Swift-də ekzistensial tiplər (protocol as type) dəyəri xüsusi konteynerə (existential container) yığır. Bu, protokol sərhədlərində retain/release sayını artırır. Swift 5.7+-da opaque result types və some parametrləri konteyneri aradan qaldıraraq əlavə yükü azaldır.
Swift-də retain count-u oxumaq üçün birbaşa API yoxdur — bu tətbiq detayı hesab olunur. Diaqnostika üçün Xcode-da Instruments (Allocations, Leaks) və ya Memory Debugger istifadə edin. Bu alətlər sinfin canlı instansiyalarının sayını və saxlama zəncirini göstərir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun