Unowned Reference (مرجع بدون مالک) — مرجعی غیرمالک در Swift است که retain count شیء را افزایش نمیدهد و برخلاف weak، پس از آزادسازی شیء به nil تنظیم نمیشود. به گفته Apple Swift Language Guide, 2026، unowned زمانی استفاده میشود که تضمین شده شیء حداقل به اندازه شیء ارجاعدهنده زنده بماند. برخلاف Weak Reference، unowned نیازی به unwrap ندارد — این یک نوع non-optional است که کد را تمیزتر میکند اما مسئولیت تضمین عمر را بر عهده توسعهدهنده میگذارد.
نکات اصلی
Unowned Reference — مرجعی غیرمالک به یک شیء در ARC است که retain count آن را افزایش نمیدهد. برخلاف weak، unowned پس از deallocation شیء صفر نمیشود: همچنان به ناحیه حافظهای اشاره میکند که قبلاً آزاد شده است. دسترسی به چنین مرجعی باعث runtime crash با EXC_BAD_ACCESS میشود.
اصطلاح «بدون مالک» معناشناسی را منعکس میکند: شیء وجود دارد اما هیچکس مسئول عمر آن نیست. توسعهدهنده صریحاً اعلام میکند: «من تضمین میکنم که این شیء تا زمانی که به آن ارجاع میدهم زنده خواهد ماند». کامپایلر این تضمین را بررسی نمیکند — این یک قرارداد در سطح توسعهدهنده است.
به گفته Swift.org Documentation, 2026، مراجع unowned در سناریوهای با عمر تضمینشده بر weak ترجیح داده میشوند زیرا: نوع optional نیاز ندارند (کد تمیزتر)، نیاز به unwrap ندارند (force-unwrap یا guard let کمتر) و overhead جدول zeroing weak را ندارند. با این حال، هر نقض قرارداد — crash.
در Swift، مراجع unowned با کلمه کلیدی unowned قبل از let یا var اعلام میشوند. برخلاف weak، unowned میتواند هم let و هم var باشد و به نوع optional نیاز ندارد. این ویژگی unowned را برای مراجعی که بر اساس منطق دامنه نمیتوانند nil باشند مناسب میکند.
class Country {
let name: String
var capital: City! // پس از مقداردهی اولیه تنظیم خواهد شد
init(name: String) { self.name = name }
}
class City {
let name: String
unowned let country: Country // ✅ unowned let — تضمین عمر
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
// استفاده
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — بدون retain cycle
در این مثال City unowned let country — شهر بدون کشور نمیتواند وجود داشته باشد. اگر کشور ناپدید شود، شهر (و مرجع) بیمعنا میشوند. از نظر معنایی این حالت ایدهآل برای unowned است: تضمین عمر وجود دارد، optional لازم نیست، retain cycle ایجاد نمیشود.
unowned var مجاز است اما کمتر رایج است. زمانی استفاده میشود که مرجع ممکن است جایگزین شود (مثلاً اتصال فرزند به والد دیگر). در هنگام جایگزینی، آزادسازی شیء قدیمی — مسئولیت مالک خارجی است.
در Swift 5.0+ پشتیبانی از unowned optional اضافه شد (unowned let x: Type?). این یک سازش است: unowned تضمین میکند که اگر مرجع nil نباشد، شیء زنده است. رفتار هنگام آزادسازی — crash، مانند unowned معمولی.
انتخاب بین unowned و weak — یکی از تصمیمهای رایج در طراحی معماری Swift است. معیارها و توصیهها را برای هر مورد بررسی میکنیم.
| معیار | Weak | Unowned |
|---|---|---|
| Optional | بله (Type?) | خیر (Type) |
| صفر شدن در deallocation | خودکار به nil | خیر (ریسک اشاره گر آویزان) |
| نوع (let/var) | فقط var | let یا var |
| عملکرد | هزینه اضافی جدول weak | حداقل (اشاره گر ساده) |
| ایمنی | ایمن (nil بررسی میشود) | ریسک EXC_BAD_ACCESS |
| تضمین عمر | نیاز نیست | تضمین صریح لازم است |
اگر حتی کوچکترین شک در مورد عمر شیء وجود دارد، از weak استفاده کنید. Weak ایمن، قابل فهم و بدون نیاز به اثبات است. از unowned استفاده کنید فقط زمانی که همه سناریوهایی که شیء میتواند زودتر آزاد شود را رد کردهاید. موارد typical: فرزندی که بدون والد وجود ندارد؛ closure که به صورت synchronous اجرا میشود؛ ارجاع به شیء در محدوده init آن.
به گفته Airbnb Swift Style Guide, 2025، در پایگاههای کد بزرگ توصیه میشود به طور پیشفرض از weak استفاده شود و unowned — فقط با یک توضیح صریح که تضمین عمر را توضیح میدهد. این امر ریسک crashهای غیرمنتظره در بازآفرینی را کاهش میدهد.
Closureها — دومین سناریوی رایج استفاده از unowned پس از روابط parent-child. Capture list [unowned self] زمانی استفاده میشود که self تضمیناً بیشتر از closure زنده است. سناریوهای درست و نادرست را بررسی میکنیم.
Closureهای synchronous — sorted, filter, map. آنها فوراً در thread فعلی اجرا میشوند، self قطعاً زنده است. Capture list با unowned در اینجا قابل قبول است و کد تمیزتری میدهد.
class DataProcessor {
var items: [Int] = [3, 1, 4, 1, 5]
func processSorted() {
// ✅ unowned self — sorted به صورت synchronous اجرا میشود، self قطعاً زنده است
let sorted = items.sorted { [unowned self] a, b in
return self.customCompare(a, b)
}
}
func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}
Closureهای asynchronous — با تأخیر، درخواستهای شبکه، انیمیشنها. Self ممکن است بین قرارگیری closure و اجرای آن آزاد شود. اینجا unowned self → crash. از [weak self] استفاده کنید.
class NetworkLoader {
func loadData() {
// ❌ خطرناک: unowned self در closure ناهمگام
URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
self.handleResponse(data) // CRASH اگر self آزاد شده باشد
}.resume()
}
func handleResponse(_ data: Data?) { }
// ✅ درست: weak self + guard
func loadDataSafe() {
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
guard let self else { return }
self.handleResponse(data)
}.resume()
}
}
قاعده را به خاطر بسپارید: unowned self — فقط برای closureهای synchronous که فوراً اجرا میشوند. برای asynchronous — همیشه weak self + guard let. استثنا: اگر به طور صریح مرجعی به شیء تا پایان closure نگه دارید (مثلاً با ذخیره یک capture قوی در متغیر دیگر).
Unowned — ابزاری قدرتمند اما خطرناک. سناریوهای واقعی که در آنها unowned میتواند منجر به crash شود و روشهای کمینهسازی ریسک را بررسی میکنیم.
ریسک اصلی unowned — تغییر منطق کسبوکار که باعث میشود تضمین عمر دیگر برقرار نباشد. توسعهدهنده کد را بازآفرینی میکند: مالکیت را تغییر میدهد، آزادسازی با تأخیر معرفی میکند، کشافزایی اضافه میکند — و مرجع unowned به بمب ساعتی تبدیل میشود. کامپایلر هشدار نمیدهد — فقط crash روی دستگاه کاربر.
توصیه: از unowned فقط زمانی استفاده کنید که تضمین عمر واضح و مستند شده است. برای هر unowned یک توضیح اضافه کنید: چرا این مرجع ایمن است و در چه شرایطی ممکن است نقض شود.
UIKit — منطقه پرخطر برای unowned. ViewController ممکن است در هر لحظه هنگام ناوبری (pop, dismiss)، تخلیه از حافظه، تغییر جهت آزاد شود. اگر ViewController را با unowned self به closure بدهید — هنگام بازگشت از پسزمینه یا پایان انیمیشن self ممکن است nil باشد.
برای کاهش ریسک هنگام استفاده از unowned، این قوانین را دنبال کنید:
// مثال: مرجع unowned مستند با توجیه صریح
class InvoiceLineItem {
let productName: String
let price: Decimal
// unowned Invoice — InvoiceLineItem بدون Invoice نمیتواند وجود داشته باشد.
// Invoice Item را ایجاد میکند و هنگام حذف خود آن را حذف میکند.
// تضمین: Invoice حداقل به اندازه Item زنده میماند.
unowned let invoice: Invoice
init(productName: String, price: Decimal, invoice: Invoice) {
self.productName = productName
self.price = price
self.invoice = invoice
}
}
// این یک تضمین قوی است: Invoice همه Itemها را در deinit حذف میکند.
// نقض تضمین = باگ در منطق کسبوکار که باید رفع شود.
مستندسازی تضمینها — استاندارد حرفهای. در پروژههای بزرگ (Airbnb, Uber) code review نیاز به توجیه هر unowned دارد. اگر تضمین واضح نیست — از weak استفاده کنید. توضیح unowned به توسعهدهندگان آینده کمک میکند بفهمند چرا اینجا weak نیست و چه شرایطی میتواند تضمین را بشکند.
سوالات متداول
Runtime crash با EXC_BAD_ACCESS. Swift اعتبار مرجع unowned را در زمان دسترسی بررسی نمیکند — این فقط یک اشارهگر «خام» است. اگر شیء آزاد شده باشد، حافظه بازنویسی شده و دسترسی به آن منجر به crash میشود. این یک استثنای غیرقابل catching است (try-catch نیست).
بله، اگر پروتکل از AnyObject ارثبری کند. Unowned با همه انواع مرجعی کار میکند: کلاسها، پروتکلهای AnyObject، اشیاء Objective-C. انواع value (struct, enum) از unowned پشتیبانی نمیکنند زیرا در ARC شرکت نمیکنند.
زمانی که تضمین عمر مطلق و واضح است — unowned از نظر طراحی ایمنتر است: نیاز به unwrap ندارد، نمیتواند nil باشد، خطاها را پنهان نمیکند. اگر شیء بدون والد نمیتواند وجود داشته باشد، unowned این را یک قرارداد صریح میکند، در حالی که weak تضمین را مبهم میکند.
بله: unowned سریعتر است زیرا برای صفر شدن نیاز به دسترسی به جدول weak runtime ندارد. در بیشتر برنامهها تفاوت محسوس نیست، اما در سناریوهای با بار بالا با میلیونها دسترسی، unowned میتواند ۱۰–۲۰٪ سریعتر در خواندن باشد.
Refactoring — خطر اصلی برای unowned. تغییر عمر شیء (کشافزایی، عملیات asynchronous، استفاده مجدد) میتواند تضمین را نقض کند. کامپایلر هشدار نمیدهد. راه حل: در تغییر معماری به weak مهاجرت کنید یا یک توضیح هشدار اضافه کنید.
خلاصه
unowned let یا unowned var؛ میتواند non-optional و optional باشد (Swift 5.0+)ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید