Unowned Reference: چیست، نحو و کاربرد در برنامه‌های موبایل

نویسنده: IT Sectr منتشر شده: 2026-03-30 زمان مطالعه: 9 دقیقه

Unowned Reference (مرجع بدون مالک) — مرجعی غیرمالک در Swift است که retain count شیء را افزایش نمی‌دهد و برخلاف weak، پس از آزادسازی شیء به nil تنظیم نمی‌شود. به گفته Apple Swift Language Guide, 2026، unowned زمانی استفاده می‌شود که تضمین شده شیء حداقل به اندازه شیء ارجاع‌دهنده زنده بماند. برخلاف Weak Reference، unowned نیازی به unwrap ندارد — این یک نوع non-optional است که کد را تمیزتر می‌کند اما مسئولیت تضمین عمر را بر عهده توسعه‌دهنده می‌گذارد.

نکات اصلی

  • Unowned Reference — مرجع غیرمالک بدون صفر شدن خودکار؛ non-optional، retain count را افزایش نمی‌دهد
  • تضمین — زمانی استفاده می‌شود که شیء تضمیناً نمی‌تواند قبل از مرجع‌دهنده آزاد شود
  • تفاوت با weak — unowned به nil صفر نمی‌شود (ریسک crash)، weak صفر می‌شود (ایمن)
  • سناریوها — parent-child با تضمین عمر، closures با unowned self، Singleton‌ها و Service Locator
  • ریسک — دسترسی به شیء unowned آزادشده باعث runtime crash (EXC_BAD_ACCESS) می‌شود

Unowned Reference چیست؟

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.

نحو unowned در Swift

در Swift، مراجع unowned با کلمه کلیدی unowned قبل از let یا var اعلام می‌شوند. برخلاف weak، unowned می‌تواند هم let و هم var باشد و به نوع optional نیاز ندارد. این ویژگی unowned را برای مراجعی که بر اساس منطق دامنه نمی‌توانند nil باشند مناسب می‌کند.

swift
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

unowned var مجاز است اما کمتر رایج است. زمانی استفاده می‌شود که مرجع ممکن است جایگزین شود (مثلاً اتصال فرزند به والد دیگر). در هنگام جایگزینی، آزادسازی شیء قدیمی — مسئولیت مالک خارجی است.

Unowned Optional

در Swift 5.0+ پشتیبانی از unowned optional اضافه شد (unowned let x: Type?). این یک سازش است: unowned تضمین می‌کند که اگر مرجع nil نباشد، شیء زنده است. رفتار هنگام آزادسازی — crash، مانند unowned معمولی.

Unowned vs Weak: چه زمانی از کدام استفاده کنیم

انتخاب بین unowned و weak — یکی از تصمیم‌های رایج در طراحی معماری Swift است. معیارها و توصیه‌ها را برای هر مورد بررسی می‌کنیم.

معیارWeakUnowned
Optionalبله (Type?)خیر (Type)
صفر شدن در deallocationخودکار به nilخیر (ریسک اشاره گر آویزان)
نوع (let/var)فقط varlet یا var
عملکردهزینه اضافی جدول weakحداقل (اشاره گر ساده)
ایمنیایمن (nil بررسی می‌شود)ریسک EXC_BAD_ACCESS
تضمین عمرنیاز نیستتضمین صریح لازم است

قاعده عملی

اگر حتی کوچکترین شک در مورد عمر شیء وجود دارد، از weak استفاده کنید. Weak ایمن، قابل فهم و بدون نیاز به اثبات است. از unowned استفاده کنید فقط زمانی که همه سناریوهایی که شیء می‌تواند زودتر آزاد شود را رد کرده‌اید. موارد typical: فرزندی که بدون والد وجود ندارد؛ closure که به صورت synchronous اجرا می‌شود؛ ارجاع به شیء در محدوده init آن.

به گفته Airbnb Swift Style Guide, 2025، در پایگاه‌های کد بزرگ توصیه می‌شود به طور پیش‌فرض از weak استفاده شود و unowned — فقط با یک توضیح صریح که تضمین عمر را توضیح می‌دهد. این امر ریسک crashهای غیرمنتظره در بازآفرینی را کاهش می‌دهد.

Unowned self در closures

Closureها — دومین سناریوی رایج استفاده از unowned پس از روابط parent-child. Capture list [unowned self] زمانی استفاده می‌شود که self تضمیناً بیشتر از closure زنده است. سناریوهای درست و نادرست را بررسی می‌کنیم.

چه زمانی unowned self ایمن است

Closureهای synchronous — sorted, filter, map. آنها فوراً در thread فعلی اجرا می‌شوند، self قطعاً زنده است. Capture list با unowned در اینجا قابل قبول است و کد تمیزتری می‌دهد.

swift
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 }
}

چه زمانی unowned self خطرناک است

Closureهای asynchronous — با تأخیر، درخواست‌های شبکه، انیمیشن‌ها. Self ممکن است بین قرارگیری closure و اجرای آن آزاد شود. اینجا unowned self → crash. از [weak self] استفاده کنید.

swift
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 — ابزاری قدرتمند اما خطرناک. سناریوهای واقعی که در آنها unowned می‌تواند منجر به crash شود و روش‌های کمینه‌سازی ریسک را بررسی می‌کنیم.

بازآفرینی و تغییر تضمین‌ها

ریسک اصلی unowned — تغییر منطق کسب‌وکار که باعث می‌شود تضمین عمر دیگر برقرار نباشد. توسعه‌دهنده کد را بازآفرینی می‌کند: مالکیت را تغییر می‌دهد، آزادسازی با تأخیر معرفی می‌کند، کش‌افزایی اضافه می‌کند — و مرجع unowned به بمب ساعتی تبدیل می‌شود. کامپایلر هشدار نمی‌دهد — فقط crash روی دستگاه کاربر.

توصیه: از unowned فقط زمانی استفاده کنید که تضمین عمر واضح و مستند شده است. برای هر unowned یک توضیح اضافه کنید: چرا این مرجع ایمن است و در چه شرایطی ممکن است نقض شود.

Unowned در سلسله‌مراتب UIKit

UIKit — منطقه پرخطر برای unowned. ViewController ممکن است در هر لحظه هنگام ناوبری (pop, dismiss)، تخلیه از حافظه، تغییر جهت آزاد شود. اگر ViewController را با unowned self به closure بدهید — هنگام بازگشت از پس‌زمینه یا پایان انیمیشن self ممکن است nil باشد.

بهترین روش‌ها

برای کاهش ریسک هنگام استفاده از unowned، این قوانین را دنبال کنید:

  • به طور پیش‌فرض weak را ترجیح دهید — weak ایمن است، unowned بهینه‌سازی است نه استاندارد
  • تضمین‌ها را مستند کنید — برای هر unowned توضیحی با دلیل بنویسید
  • در ViewController از unowned اجتناب کنید — چرخه حیات UIKit برای تضمین‌های unowned غیرقابل پیش‌بینی است
  • Unowned را فقط برای closureهای synchronous استفاده کنید — sorted, filter, map — کاندیدهای ایمن
  • در code review بررسی کنید — هر unowned نیاز به توجیه از طرف نویسنده کد دارد
  • در کوچکترین شک به weak مهاجرت کنید — از دست دادن در خوانایی (یک guard let) کمتر از crash در محیط تولید است
swift
// مثال: مرجع 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 نیست و چه شرایطی می‌تواند تضمین را بشکند.

سوالات متداول

پس از آزادسازی شیء، هنگام دسترسی به مرجع unowned چه اتفاقی می‌افتد؟

Runtime crash با EXC_BAD_ACCESS. Swift اعتبار مرجع unowned را در زمان دسترسی بررسی نمی‌کند — این فقط یک اشاره‌گر «خام» است. اگر شیء آزاد شده باشد، حافظه بازنویسی شده و دسترسی به آن منجر به crash می‌شود. این یک استثنای غیرقابل catching است (try-catch نیست).

آیا می‌توان از unowned با پروتکل‌ها استفاده کرد؟

بله، اگر پروتکل از AnyObject ارث‌بری کند. Unowned با همه انواع مرجعی کار می‌کند: کلاس‌ها، پروتکل‌های AnyObject، اشیاء Objective-C. انواع value (struct, enum) از unowned پشتیبانی نمی‌کنند زیرا در ARC شرکت نمی‌کنند.

چه زمانی unowned از weak ایمن‌تر است؟

زمانی که تضمین عمر مطلق و واضح است — unowned از نظر طراحی ایمن‌تر است: نیاز به unwrap ندارد، نمی‌تواند nil باشد، خطاها را پنهان نمی‌کند. اگر شیء بدون والد نمی‌تواند وجود داشته باشد، unowned این را یک قرارداد صریح می‌کند، در حالی که weak تضمین را مبهم می‌کند.

آیا تفاوت عملکردی بین unowned و weak وجود دارد؟

بله: unowned سریع‌تر است زیرا برای صفر شدن نیاز به دسترسی به جدول weak runtime ندارد. در بیشتر برنامه‌ها تفاوت محسوس نیست، اما در سناریوهای با بار بالا با میلیون‌ها دسترسی، unowned می‌تواند ۱۰–۲۰٪ سریع‌تر در خواندن باشد.

چگونه refactoring بر تضمین‌های unowned تأثیر می‌گذارد؟

Refactoring — خطر اصلی برای unowned. تغییر عمر شیء (کش‌افزایی، عملیات asynchronous، استفاده مجدد) می‌تواند تضمین را نقض کند. کامپایلر هشدار نمی‌دهد. راه حل: در تغییر معماری به weak مهاجرت کنید یا یک توضیح هشدار اضافه کنید.

خلاصه

  • Unowned Reference — مرجع غیرمالک بدون صفر شدن؛ non-optional، retain count را افزایش نمی‌دهد
  • تضمین — نیاز به اثبات صریح دارد که شیء کمتر از کد ارجاع‌دهنده عمر نمی‌کند
  • نحوunowned let یا unowned var؛ می‌تواند non-optional و optional باشد (Swift 5.0+)
  • Unowned vs Weak — unowned سریع‌تر و تمیزتر است اما weak ایمن‌تر است؛ weak — انتخاب پیش‌فرض
  • Closureها — unowned self فقط برای closureهای synchronous؛ asynchronous نیاز به [weak self] دارند
  • مستندسازی — هر unowned باید توضیحی با دلیل تضمین داشته باشد
  • توصیه — در صورت تردید weak را انتخاب کنید؛ unowned — برای قراردادهای صریح و مستند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید