Automatic Reference Counting (ARC) — سیستم مدیریت حافظه در Swift و Objective-C است که بهطور خودکار تعداد مراجع به هر شیء را شمارش کرده و پس از رسیدن شمارنده به صفر، آن را آزاد میکند. به استناد به Apple Swift Documentation, 2026، ARC در کامپایلر ساخته شده و در مرحله کامپایل کار میکند و در مکانهای مورد نیاز فراخوانیهای retain/release را قرار میدهد. بر خلاف Garbage Collection، ARC نیازی به رشته جداگانه زبالهگیر ندارد و در زمان اجرای برنامه مکافت ایجاد نمیکند.
نکات کلیدی
ARC (Automatic Reference Counting) — یک مکانیسم مدیریت حافظه کامپایلری است که توسط Apple در Xcode 4.2 (2011) برای Objective-C معرفی شد و توسط Swift به ارث برده شد. بر خلاف مدیریت دستی حافظه (Manual Retain-Release، MRR)، ARC فراخوانیهای retain، release و autorelease را کاملاً آتوماتیک کرده و آنها را در مرحله کامپایل بدون مشارکت توسعهدهنده قرار میدهد.
ARC یک زبالهگیر نیست. این یک تحلیل استاتیک با درج دینامیک کد است: کامپایلر عمر شیئها را تحلیل کرده و retain/release را در نقاطی که شیئها ایجاد، کپی یا از حدوده خروجی میشوند، قرار میدهد. نتیجه — آزادسازی تعیینپذیر حافظه: شیء دقیقاً در همان موقعی که دیگر به آن ارجاعی نمیشود، بدون تأخیر و مکافت حذف میشود.
به استناد به WWDC 2011 Session 323، انتقال از MRR به ARC تعداد باگهای کراش مربوط به حافظه را در برنامههای Apple تا 70% کاهش داد. توسعهدهندگان دیگر به صورت دستی retain/release را متوازن نمیکردند، که این کل طبقهای از نشتها و خطاهای double-free را برطرف کرد.
هر شیء در حافظه یک شمارنده مرجع (retain count) دارد. هنگام ایجاد شیء، شمارنده روی 1 قرار میگیرد. وقتی یک مرجع strong جدید به شیء اشاره میکند — شمارنده افزایش مییابد (retain). وقتی مرجع strong ناپدید میشود — شمارنده کاهش مییابد (release). با رسیدن به صفر، شیء بلافاصله دیلوکیت میشود.
کامپایلر Swift retain/release را در هر تنظیم قرار نمیدهد — از تحلیل استاتیک برای بهینهسازی استفاده میکند. به عنوان مثال، اگر شیء پس از انتقال استفاده نخواهد شد، کامپایلر میتواند release/retain ضایع را حذف کند. این بهینهسازی ARC Optimisation نامیده میشود.
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) مقداردهی شد (retain count: 1)")
}
deinit {
print("\(name) دیلوکیت شد")
}
}
func testARC() {
let p = Person(name: "Alice") // retain count = 1
let q = p // retain count = 2
// q از حدوده خارج میشود
// retain count = 1
// p از حدوده خارج میشود
// retain count = 0 → deinit
}
در این مثال مشاهده میشود که ARC چگونه شمارنده را مدیریت میکند: هنگام تنظیم q = p، شمارنده افزایش مییابد، و هنگام خروج q از حدوده — کاهش مییابد. وقتی آخرین مرجع strong ناپدید میشود، دیاینیشیالیزاتور بلافاصله فراخوانده میشود. هیچ زبالهگیری منتظر نمیماند — حافظه بلافاصله آزاد میشود.
ARC و Garbage Collection یک مسئله را حل میکنند — مدیریت خودکار حافظه — اما با رویکردهای اصولاً متفاوت. انتخاب بین آنها معماری زبان را مشخص میکند: Swift (ARC) در مقابل Java/Go (GC). بیایید تفاوتهای اصلی را بررسی کنیم.
| ویژگی | ARC (Swift/ObjC) | GC (Java/Go) |
|---|---|---|
| زمان آزادسازی | تعیینپذیر: بلافاصله پس از صفر شدن شمارنده | غیرتعیینپذیر: در جمعآوری بعدی |
| مکافت اجرا | ندارد (درج retain/release در مرحله کامپایل) | مکافت Stop-The-World دارد (2–200 میلیثانیه) |
| سرراهد | افزایش/کاهش شمارنده در هر مرجع | پیمایش گراف شیئها، علامتگذاری، آزادسازی |
| مشکلات | Retain Cycle (حل دستی) | تکه تکه شدن هیپ، نشت در مراجع فراموش شده |
| رشته اضافی | نیاز ندارد | نیاز به رشته زبالهگیر دارد |
تسویه کلیدی: ARC عمر قابل پیشبینی برای شیئها و مکافت صفر فراهم میکند، اما از توسعهدهنده درک retain cycle و انتخاب صحیح weak/unowned را میطلبد. GC از این دغدغهها آزاد میکند، اما به بهای مکافتهای غیرتعیینپذیر و رشته اضافی.
ARC سه نوع کلیدواژه مرجع تعریف میکند، که هر کدام بهطور متفاوت بر شمارنده و چرخه عمر شیء تأثیر میگذارد. انتخاب صحیح کلیدواژه اساس کار ایمن با حافظه در Swift است.
Strong — کلیدواژه پیشفرض. هر مرجع strong شمارنده retain شیء را 1 واحد افزایش میدهد. تا زمانی که حداقل یک مرجع strong وجود داشته باشد، شیء زنده است. تمام ویژگیهای کلاسها و متغیرهای محلی در Swift بهطور پیشفرض strong هستند. مراجع strong یک رابطه مالکیت ایجاد میکنند: شیء A مالک شیء B است.
Weak — مرجعی که شمارنده retain را افزایش نمیدهد. شیء میتواند دیلوکیت شود، حتی اگر یک مرجع weak به آن اشاره کند. پس از دیلوکیشن، مرجع weak بهطور خودکار به nil تنظیم میشود. مراجع weak همیشه به عنوان var با نوع اختیاری (?) اعلام میشوند. آنها برای شکستن چرخه retain استفاده میشوند، خصوصاً در الگوی delegate.
Unowned — مرجع غیرمالک که مانند weak شمارنده retain را افزایش نمیدهد. اما مرجع unowned پس از دیلوکیشن به nil تنظیم نمیشود — دسترسی به شیء آزادشده باعث کراش میشود. Unowned زمانی استفاده میشود که تضمین شده باشد شیء حداقل به اندازه شیء مرجعدهنده عمر میکند. سناریو تیپیکی — بستهها (closures) و روابط والد-فرزند با عمر تضمینی.
class Customer {
let name: String
var card: CreditCard? // strong
init(name: String) { self.name = name }
deinit { print("\(name) دیلوکیت شد") }
}
class CreditCard {
let number: String
unowned let customer: Customer // unowned — مالک نیست
init(number: String, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("کارت \(number) دیلوکیت شد") }
}
var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer و CreditCard هر دو آزاد شدند — retain cycle نیست
در اینجا CreditCard از مرجع unowned به Customer استفاده میکند. Customer مالک کارت است (strong)، و کارت مالک مشتری نیست (unowned). وقتی Customer nil شود، هر دو شیء آزاد میشوند — retain cycle ایجاد نمیشود. اگر card.customer strong بود، چرخه آزادسازی را مسدود میکرد.
علیرغم آتوماتیک بودن، ARC پناسئه نیست. توسعهدهندگان با چند مشکل تیپیک مواجه میشوند که نیازمند درک مکانیسم داخلی مدیریت حافظه است.
بستهها (closures) در Swift متغیرهای خارجی را از طریق مرجع strong برداشته میکنند. اگر بسته به یک ویژگی کلاس تنظیم شود و self را برداشته کند — retain cycle ایجاد میشود: کلاس بسته را، بسته self را نگه میدارد. راهحل — capture list با weak یا unowned.
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] یک مرجع weak به self داخل بسته ایجاد میکند. این retain cycle ممکن را میشکند. Guard let self تضمین میکند که شیء قبل از اجرای کد زنده است. weak self — روش استاندارد برای بستههای ناهمگام در Swift.
با وجود آن که retain/release عملیاتهای سبکی هستند، در حلقههای گرم افزایش/کاهش مکرر شمارنده سرراهد ایجاد میکند. در Swift 5.9+، کامپایلر از بهینهسازی استفاده میکند که در آن retain/release های اضافی حذف میشوند اگر تحلیلگر ایمنی را ثابت کند. با این حال، در Objective-C هنوز retain/release میتوانند در سناریوهای با بار بالا با میلیونها فراخوانی در ثانیه گردنه باشند.
Autorelease Pool — مکانیسم تأخیر release است که در Objective-C و برخی سناریوهای Swift استفاده میشود. شیئها در یک پول قرار میگیرند و هنگام drain پول، release میگیرند. در حلقههایی با تعداد زیاد شیئهای موقت (مانند تجزیه و تحلیل JSON)، ایجاد autoreleasepool خود افت مصرف حافظه اصلی را کاهش میدهد.
سوالات متداول
در مدیریت دستی (MRR)، توسعهدهنده به صورت صریح retain، release و autorelease را فراخوان میکرد. ARC این فراخوانیها را بهطور خودکار در مرحله کامپایل قرار میدهد، ریسک double-free، نشت به دلیل فراموشی release و خطاهای توازن retain/release را برطرف میکند.
ARC فقط شیئهای Objective-C و کلاسهای Swift را مدیریت میکند. برای ساختارها و پوینترهای C/C++، ARC اعمال نمیشود — این شیئها به صورت دستی یا از طریق پوینترهای هوشمند C++ (shared_ptr, unique_ptr) مدیریت میشوند. شیئهای Core Foundation (CFString, CGColor) نیز تحت ARC قرار نمیگیرند.
weak — وقتی شیء میتواند زودتر از شیء مرجعدهنده دیلوکیت شود (delegates، بستههای ناهمگام). unowned — وقتی تضمین شده باشد شیء حداقل به اندازه شیء مرجعدهنده عمر میکند (والد-فرزند، که فرزند نمیتواند بدون والد وجود داشته باشد). اگر مطمئن نیستید — weak را انتخاب کنید.
انواع اکزیستانشیال (protocol as type) در Swift مقدار را در یک کانتینر خاص (existential container) بستهبندی میکنند. این تعداد retain/release را در مرزهای پروتکل افزایش میدهد. در Swift 5.7+، opaque result types و پارامترهای some با حذف کانتینر، سرراهد را کاهش میدهند.
برای خواندن retain count در Swift API مستقیمی وجود ندارد — این جزئیات پیادهسازی محسوب میشود. برای دیاگنوز از Instruments (Allocations, Leaks) یا Memory Debugger در Xcode استفاده کنید. این ابزارها تعداد نمونههای زنده کلاس و زنجیره نگهداری را نشان میدهند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید