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 — إنه نوع غير اختياري، مما يجعل الكود أنظف لكنه يضع المسؤولية على المطور لضمان عمر الكائن.

النقاط الرئيسية

  • Unowned Reference — مرجع غير مالك دون تصفير تلقائي؛ غير اختياري، لا يزيد retain count
  • الضمان — يُستخدم عندما يكون مضموناً أن الكائن لا يمكن تحريره قبل الكائن الذي يشير إليه
  • الفرق عن weak — unowned لا يُصفّر إلى nil (خطر انهيار)، weak يُصفّر (آمن)
  • السيناريوهات — أب-ابن مع ضمان العمر، closures مع unowned self، المفردات و Service Locator
  • الخطر — الوصول إلى كائن unowned مُحرر يسبب انهياراً في وقت التشغيل (EXC_BAD_ACCESS)

ما هو Unowned Reference؟

Unowned Reference هو مرجع غير مالك لكائن في ARC لا يزيد retain count الخاص به. على عكس weak، المرجع unowned لا يُصفّر بعد تحرير الكائن: يستمر في الإشارة إلى ذاكرة تم تحريرها بالفعل. الوصول إلى مثل هذا المرجع يسبب انهياراً في وقت التشغيل مع EXC_BAD_ACCESS.

مصطلح «غير مملوك» يعكس الدلالات: الكائن موجود، لكن لا أحد مسؤول عن عمره. المطور يصرح صراحة: «أضمن أن هذا الكائن سيكون حياً طالما أشير إليه». المترجم لا يتحقق من هذا الضمان — إنه عقد على مستوى المطور.

وفقاً لـ Swift.org Documentation, 2026، المراجع unowned مفضلة على weak في السيناريوهات ذات العمر المضمون لأنها: لا تتطلب نوعاً اختيارياً (كود أنظف)، لا تتطلب unwrap (تقليل force-unwrap أو guard let)، وليس لها عبء إدارة جدول weak للتصفير. لكن أي خرق للعقد يؤدي إلى انهيار.

بناء جملة unowned في Swift

في Swift، تُصرح المراجع unowned بالكلمة المفتاحية unowned قبل let أو var. على عكس weak، يمكن أن يكون unowned كلاً من let و var، ولا يتطلب نوعاً اختيارياً. هذه الخاصية تجعل 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: ضمان العمر موجود، لا حاجة للاختياري، لا يحدث retain cycle.

unowned var

unowned var مسموح به لكنه أقل شيوعاً. يُستخدم عندما يمكن استبدال المرجع (مثلاً، إعادة ربط طفل بأب مختلف). عند الاستبدال، تحرير الكائن القديم هو مسؤولية المالك الخارجي.

Unowned Optional

في Swift 5.0+، تم تقديم دعم unowned الاختياري (unowned let x: Type?). هذا حل وسط: unowned يضمن أنه إذا لم يكن المرجع nil، فالكائن حي. السلوك عند التحرير هو انهيار، كما هو الحال مع unowned العادي.

Unowned vs Weak: متى تستخدم أياً منهما

الاختيار بين unowned و weak هو أحد القرارات المتكررة عند تصميم بنية Swift. دعنا نفحص المعايير والتوصيات لكل حالة.

المعيارWeakUnowned
اختيارينعم (Type?)لا (Type)
التصفير عند التحريرتلقائي إلى nilلا (خطر مؤشر معلق)
النوع (let/var)var فقطlet أو var
الأداءعبء جدول weakأدنى حد (مؤشر بسيط)
الأمانآمن (nil يُفحص)خطر EXC_BAD_ACCESS
ضمان العمرغير مطلوبمطلوب ضمان صريح

قاعدة عملية

استخدم weak إذا كان هناك أدنى شك حول عمر الكائن. Weak آمن وواضح ولا يتطلب دليلاً. استخدم unowned فقط عندما تتمكن من استبعاد جميع السيناريوهات التي يمكن فيها تحرير الكائن مبكراً. الحالات النموذجية: طفل لا يوجد بدون أب؛ closure ينفذ بشكل متزامن؛ الوصول إلى كائن داخل المُهيئ الخاص به.

وفقاً لـ Airbnb Swift Style Guide, 2025، في قواعد الأكواد الكبيرة يُوصى باستخدام weak افتراضياً و unowned فقط مع تعليق صريح يشرح ضمان العمر. هذا يقلل من خطر الأعطال غير الواضحة أثناء إعادة الهيكلة.

Unowned self في Closures

الـ closures هي ثاني أكثر حالات استخدام unowned شيوعاً بعد علاقات الأب-الابن. قائمة الالتقاط [unowned self] تُستخدم عندما يكون مضموناً أن self يعيش أطول من closure. دعنا نفحص السيناريوهات الصحيحة والخاطئة.

متى يكون unowned self آمناً

الـ closures المتزامنة — sorted, filter, map. يتم تنفيذها فوراً في الخيط الحالي، self بالتأكيد حي. قائمة الالتقاط مع unowned مقبولة هنا وتنتج كوداً أنظف.

swift
class DataProcessor {
    var items: [Int] = [3, 1, 4, 1, 5]

    func processSorted() {
        // ✅ unowned self — sorted ينفذ بشكل متزامن، 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 خطيراً

الـ closures غير المتزامنة — مع التأخيرات، طلبات الشبكة، الرسوم المتحركة. قد يتم تحرير self بين جدولة closure وتنفيذه. هنا unowned self يؤدي إلى انهيار. استخدم [weak self].

swift
class NetworkLoader {
    func loadData() {
        // ❌ خطر: unowned self في closure غير متزامن
        URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
            self.handleResponse(data)  // انهيار إذا تم تحرير 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 — فقط للـ closures المتزامنة التي تنفذ فوراً. للـ closures غير المتزامنة، استخدم دائماً weak self + guard let. استثناء: إذا كنت تحتفظ صراحة بمرجع للكائن حتى يكتمل closure (مثلاً، الاحتفاظ بمرجع قوي في متغير آخر).

مخاطر unowned وكيفية تجنبها

Unowned أداة قوية لكنها خطيرة. دعنا نفحص سيناريوهات واقعية حيث يمكن أن يؤدي unowned إلى أعطال وطرق لتقليل المخاطر.

إعادة الهيكلة وتغيير الضمانات

الخطر الرئيسي لـ unowned هو تغيير في منطق الأعمال يبطل ضمان العمر. مطور يعيد هيكلة الكود: يغير الملكية، يقدم تحريراً مؤجلاً، يضيف تخزيناً مؤقتاً — ويصبح المرجع unowned قنبلة موقوتة. المترجم لن يحذرك — فقط انهيار على جهاز المستخدم.

توصية: استخدم unowned فقط عندما يكون ضمان العمر واضحاً وموثقاً. أضف تعليقاً إلى كل unowned: لماذا هذا المرجع آمن وتحت أي ظروف يمكن انتهاكه.

Unowned في التسلسلات الهرمية UIKit

UIKit منطقة عالية المخاطر لـ unowned. يمكن تحرير ViewController في أي لحظة أثناء التنقل (pop, dismiss)، تفريغ الذاكرة، تغييرات الاتجاه. إذا مررت ViewController إلى closure مع unowned self، قد يكون self nil عند العودة من الخلفية أو عند اكتمال الرسم المتحرك.

أفضل الممارسات

لتقليل المخاطر عند استخدام unowned، اتبع هذه القواعد:

  • فضل weak افتراضياً — weak آمن، unowned هو تحسين وليس معياراً
  • وثق الضمانات — لكل unowned، اكتب تعليقاً مع التبرير
  • تجنب unowned في ViewController — دورة حياة UIKit غير متوقعة لضمانات unowned
  • استخدم unowned فقط للـ closures المتزامنة — sorted, filter, map مرشحون آمنون
  • تحقق أثناء مراجعة الكود — كل unowned يتطلب تبريراً من مؤلف الكود
  • هاجر إلى weak عند أدنى شك — الخسارة في القراءة (guard let واحد) أقل من انهيار في الإنتاج
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 يزيل كل Items في deinit.
// انتهاك الضمان = خطأ في منطق الأعمال يجب إصلاحه.

توثيق الضمانات هو معيار مهني. في المشاريع الكبيرة (Airbnb, Uber)، مراجعة الكود تتطلب تبريراً لكل unowned. إذا كان الضمان غير واضح، استخدم weak. تعليق على unowned يساعد المطورين المستقبليين على فهم لماذا لم يُستخدم weak هنا وما الظروف التي قد تكسر الضمان.

الأسئلة الشائعة

ماذا يحدث عند الوصول إلى مرجع unowned بعد تحرير الكائن؟

انهيار في وقت التشغيل مع EXC_BAD_ACCESS. Swift لا يتحقق من صحة المرجع unowned عند الوصول — إنه مجرد مؤشر «خام». إذا تم تحرير الكائن، يتم استبدال الذاكرة، والوصول إليها ينتهي بشكل كارثي. هذا استثناء غير قابل للالتقاط (ليس try-catch).

هل يمكن استخدام unowned مع البروتوكولات؟

نعم، إذا كان البروتوكول موروثاً من AnyObject. Unowned يعمل مع جميع أنواع المراجع: الكلاسات، بروتوكولات AnyObject، كائنات Objective-C. أنواع القيم (struct, enum) لا تدعم unowned لأنها لا تشارك في ARC.

متى يكون unowned أكثر أماناً من weak؟

عندما يكون ضمان العمر مطلقاً وواضحاً — unowned أكثر أماناً من منظور التصميم: لا يتطلب unwrap، لا يمكن أن يكون nil، ولا يخفي الأخطاء. إذا كان الكائن لا يمكن أن يوجد بدون أب، unowned يجعله عقداً صريحاً، بينما weak يضعف الضمان.

هل هناك فرق في الأداء بين unowned و weak؟

نعم: unowned أسرع لأنه لا يتطلب الوصول إلى جدول weak في وقت التشغيل للتصفير. في معظم التطبيقات الفرق غير محسوس، لكن في سيناريوهات الأحمال العالية مع ملايين الوصولات، يمكن أن يكون unowned أسرع بنسبة 10–20% في القراءة.

كيف تؤثر إعادة الهيكلة على ضمانات unowned؟

إعادة الهيكلة هي الخطر الرئيسي لـ unowned. تغيير عمر الكائن (التخزين المؤقت، العمليات غير المتزامنة، إعادة الاستخدام) يمكن أن يكسر الضمان. المترجم لن يحذرك. الحل: هاجر إلى weak عند تغيير البنية أو أضف تعليق تحذيري.

الخلاصة

  • Unowned Reference — مرجع غير مالك دون تصفير؛ غير اختياري، لا يزيد retain count
  • الضمان — يتطلب دليلاً صريحاً أن الكائن يعيش على الأقل طالما الكود الذي يشير إليه
  • بناء الجملةunowned let أو unowned var؛ يمكن أن يكون غير اختياري واختياري (Swift 5.0+)
  • Unowned vs Weak — unowned أسرع وأنظف، لكن weak أكثر أماناً؛ weak هو الخيار الافتراضي
  • Closures — unowned self فقط للـ closures المتزامنة؛ غير المتزامنة تتطلب [weak self]
  • التوثيق — كل unowned يجب أن يكون له تعليق يبرر الضمان
  • توصية — عند الشك، اختر weak؛ unowned للعقود الصريحة والموثقة

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا