Strong Reference (مضبوط حوالہ) — میموری مینجمنٹ کا ایک معیاری طریقہ کار ہے جس میں آبجیکٹ اس وقت تک میموری میں رہتا ہے جب تک اس پر کم از کم ایک فعال حوالہ اشارہ کرتا ہے۔ کمزور حوالوں کے برعکس، مضبوط حوالہ آبجیکٹ کے حوالہ کاؤنٹر کو بڑھاتا ہے اور اس کے خودکار آزاد ہونے کو روکتا ہے۔ Apple Developer Documentation کے مطابق، ARC Swift اور Objective-C میں آبجیکٹس کی زندگی کا دورانیہ خودکار طور پر منظم کرتا ہے۔ موبائل ایپلیکیشنز میں میموری لیک اور چکری انحصار کو روکنے کے لیے مضبوط حوالوں کے کام کو سمجھنا بہت ضروری ہے۔
اہم نکات
Strong Reference ایک آبجیکٹ کے حوالے کی ایک قسم ہے جو کوڑا کرکٹ جمع کرنے والے یا میموری مینجمنٹ سسٹم کے ذریعے اس کی تباہی کو روکتی ہے۔ جب تک آبجیکٹ پر کم از کم ایک مضبوط حوالہ موجود ہے، اس کی میموری آزاد نہیں ہوتی۔ یہ بنیادی طریقہ کار ہے جس پر Swift اور Objective-C میں ARC اور Java اور Kotlin میں کوڑا کرکٹ جمع کرنا مبنی ہے۔
مضبوط حوالہ کا تصور خودکار میموری مینجمنٹ والی تمام زبانوں کے لیے بنیادی ہے۔ ARC والے نظاموں میں، ہر مضبوط حوالہ آبجیکٹ کے حوالہ کاؤنٹر کو بڑھاتا ہے۔ جب کاؤنٹر صفر ہو جاتا ہے، آبجیکٹ فوری طور پر ڈی ایلوکیٹ ہو جاتا ہے۔ Java اور Kotlin میں کوڑا کرکٹ جمع کرنے کے ساتھ، مضبوط حوالہ اس بات کو یقینی بناتا ہے کہ آبجیکٹ قابل رسائی ہے اور GC کے ذریعے جمع نہیں کیا جائے گا۔
WWDC 2021 کے مطابق، iOS ایپلیکیشنز میں تقریباً 35% میموری لیک کا تعلق مضبوط حوالوں کے غلط استعمال اور retain cycles سے ہے۔ Android ڈویلپمنٹ میں، closures اور callbacks میں پوشیدہ مضبوط حوالوں کے ذریعے لیک Context Leak کے بعد میموری کے مسائل کی دوسری سب سے عام وجہ ہے۔
میموری کے ساتھ مؤثر طریقے سے کام کرنے کے لیے، آپ کو strong، weak اور unowned حوالوں کے درمیان فرق کو سمجھنا ہوگا اور ملکیت اور آبجیکٹ کی زندگی کی بنیاد پر صحیح حوالہ کی قسم کا انتخاب کرنا ہوگا۔
ARC سے پہلے، ڈویلپرز ہر آبجیکٹ کے لیے دستی طور پر retain اور release کو کال کرتے تھے، جس سے بہت سی غلطیاں ہوتی تھیں۔ ARC، جسے Apple نے 2011 میں LLVM 3.0 کے ساتھ متعارف کرایا، نے مرتب وقت پر ملکیت کے گراف کا تجزیہ کرکے اس عمل کو خودکار بنایا۔ مرتب خود ضروری جگہوں پر retain، release اور autorelease کالیں داخل کرتا ہے۔
Clang Static Analyzer کے مطابق، ARC کے تعارف نے iOS ایپلیکیشنز میں میموری سے متعلقہ بگ کو 70% تک کم کیا۔ ڈویلپرز کے لیے، اس کا مطلب ہے کہ میموری مینجمنٹ محفوظ ہو گیا ہے، لیکن ساتھ ہی یہ سمجھنے کی ضرورت پیدا ہوئی کہ مضبوط حوالے اندرونی طور پر کیسے کام کرتے ہیں — retain cycles سے بچنے کے لیے۔
Kotlin اور Java میں، کوڑا کرکٹ جمع کرنے والا ARC کا کردار ادا کرتا ہے، لیکن مضبوط حوالہ کا اصول وہی رہتا ہے: GC Roots وہ داخلے کے مقام ہیں جن کے ذریعے آبجیکٹ مضبوط حوالوں سے رکھے جاتے ہیں۔ جب تک کوئی آبجیکٹ GC Root سے مضبوط حوالوں کی زنجیر کے ذریعے قابل رسائی ہے، اسے جمع نہیں کیا جائے گا۔
ARC (Automatic Reference Counting) ہیپ میں ہر آبجیکٹ کے حوالوں کو گن کر کام کرتا ہے۔ جب کسی آبجیکٹ پر نیا مضبوط حوالہ بنایا جاتا ہے، کاؤنٹر بڑھتا ہے (retain)۔ جب حوالہ تباہ یا اوور رائٹ ہوتا ہے، کاؤنٹر گھٹتا ہے (release)۔ جب کاؤنٹر صفر تک پہنچتا ہے، آبجیکٹ فوری طور پر میموری سے ہٹا دیا جاتا ہے۔
Swift میں ایک مثال پر غور کریں۔ جب کسی کلاس کا ایک نمونہ بنایا جاتا ہے، ARC میموری مختص کرتا ہے اور retain count کو 1 پر سیٹ کرتا ہے۔ دوسرے متغیر میں ہر نئی تفویض کاؤنٹر کو بڑھاتی ہے۔ جب متغیر دائرہ کار سے باہر ہوتا ہے، کاؤنٹر گھٹتا ہے:
class ProfileViewController {
var nameLabel: String?
var avatarImage: UIImage?
func loadProfile() {
// نئے نمونے کے لیے retain count = 1
let user = User(name: "Ivan")
// nameLabel تفویض کرنے کے بعد retain count = 2
nameLabel = user.name
// طریقہ سے باہر نکلنا — user دائرہ کار سے باہر، retain count = 1
}
}
اس کوڈ میں، ARC اس بات کو یقینی بناتا ہے کہ User آبجیکٹ میموری میں اس وقت تک رہے جب تک اس پر کم از کم ایک مضبوط حوالہ اشارہ کرتا ہے۔ جب loadProfile فنکشن ختم ہوتا ہے، مقامی user متغیر تباہ ہو جاتا ہے، لیکن nameLabel اب بھی آبجیکٹ کو رکھتا ہے۔ میموری صرف اس وقت آزاد ہوگی جب nameLabel کا وجود ختم ہو جائے یا اوور رائٹ ہو جائے۔
Kotlin میں، اسی طرح کا رویہ GC Roots کے ذریعے فراہم کیا جاتا ہے۔ جب تک کوڑا کرکٹ جمع کرنے والے کی جڑ (مثلاً ایک مستحکم فیلڈ یا فعال تھریڈ) سے مضبوط حوالوں کی ایک قابل تلاش زنجیر موجود ہے، آبجیکٹ میموری میں رہتا ہے۔ فرق یہ ہے کہ GC فوری طور پر میموری آزاد نہیں کرتا — یہ رسائی کے تجزیہ کے بعد غیر متزامن طور پر ہوتا ہے۔
ARC میں، کاؤنٹر کے صفر تک پہنچنے پر آزادی ہم آہنگ طور پر ہوتی ہے۔ Swift اور Objective-C میں، آپ بالکل جانتے ہیں کہ آبجیکٹ کب ہٹایا جائے گا۔ Kotlin اور Java میں، آزادی کا لمحہ غیر متوقع ہے، لیکن اس کی تلافی کوڑا کرکٹ جمع کرنے والے کی سطح پر چکری انحصار کا پتہ لگانے کے لیے زیادہ لچکدار اسکیم سے کی جاتی ہے۔
Retain cycle (برقرار رکھنے کا چکر) — ایک ایسی صورت حال جس میں دو یا زیادہ آبجیکٹ ایک دوسرے کے لیے باہمی مضبوط حوالہ رکھتے ہیں۔ نتیجتاً، ان کا retain count کبھی صفر نہیں ہوتا اور میموری کبھی آزاد نہیں ہوتی، چاہے آبجیکٹ ایپلیکیشن کے لیے مزید ضروری نہ ہوں۔
ایک کلاسک مثال: ایک پیرنٹ ویو کنٹرولر مضبوط حوالہ کے ساتھ چائلڈ آبجیکٹ رکھتا ہے، اور وہ بدلے میں مضبوط حوالہ کے ساتھ پیرنٹ کو رکھتا ہے۔ یہ مندوبین، closures اور nested lambda اظہار والی صورتوں میں عام ہے۔ Instruments Leaks کے مطابق، retain cycles ARC استعمال کرنے والی ایپلیکیشنز میں تمام میموری لیک کا 60% تک بنتے ہیں۔
class ParentViewController: UIViewController {
var child: ChildViewController?
func setupChild() {
child = ChildViewController()
// retain cycle: والد child رکھتا ہے، child closure کے ذریعے والد رکھتا ہے
child?.onEvent = {
self.handleEvent()
}
}
func handleEvent() {}
}
یہاں مسئلہ یہ ہے کہ onEvent closure مضبوط حوالہ کے ساتھ self (ParentViewController) کو کیپچر کرتا ہے، اور ParentViewController خود مضبوط حوالہ کے ساتھ child کو رکھتا ہے۔ دونوں آبجیکٹ کبھی آزاد نہیں ہوں گے۔ حل چکر توڑنے کے لیے closure میں weak self استعمال کرنا ہے۔
Kotlin میں، بیرونی آبجیکٹ کو کیپچر کرنے والے lambdas استعمال کرتے وقت اسی طرح کے چکر پیدا ہوتے ہیں۔ JVM کوڑا کرکٹ جمع کرنے والا وقت کے ساتھ ایسے چکروں کا پتہ لگا سکتا ہے، لیکن صرف اس صورت میں جب آبجیکٹ GC Roots سے ناقابل رسائی ہوں۔ اگر چکر ایک فعال تھریڈ یا UI سیاق و سباق سے منسلک ہے، تو لیک پوری ایپلیکیشن کی زندگی تک رہتی ہے۔
حوالہ کی قسموں کے درمیان فرق کو سمجھنا محفوظ میموری مینجمنٹ کی کلید ہے۔ Strong Reference retain count بڑھاتا ہے۔ Weak Reference retain count نہیں بڑھاتا اور آبجیکٹ کے ڈی ایلوکیٹ ہونے پر خودکار طور پر nil ہو جاتا ہے۔ Unowned Reference بھی retain count نہیں بڑھاتا لیکن صفر نہیں ہوتا — ڈی ایلوکیشن کے بعد اس تک رسائی کرنے سے کریش ہوتا ہے۔
| حوالہ کی قسم | Retain count | حفاظت | کب استعمال کریں |
|---|---|---|---|
| Strong | +1 | محفوظ (پہلے سے طے شدہ) | آبجیکٹ کی ملکیت، والد → بچے کا رشتہ |
| Weak | تبدیل نہیں ہوتا | خودکار صفر کرنا (محفوظ) | مندوبین، callbacks، الٹے حوالے |
| Unowned | تبدیل نہیں ہوتا | دیر سے رسائی پر کریش کا خطرہ | جب آبجیکٹ مالک سے زیادہ زندہ رہنے کی ضمانت ہو |
حوالہ کی قسم کا انتخاب ملکیت کے رشتے سے طے ہوتا ہے۔ اگر آبجیکٹ B، A کا حصہ ہے اور اس کے بغیر وجود میں نہیں رہ سکتا — Strong استعمال کریں۔ اگر B آزادانہ طور پر وجود میں رہ سکتا ہے اور اطلاعات کے لیے A کا حوالہ دیتا ہے — Weak استعمال کریں۔ Unowned شاذ و نادر ہی استعمال ہوتا ہے — صرف اس وقت جب بچے کے آبجیکٹ کی زندگی والد کی زندگی سے زیادہ نہ ہو۔
Apple Developer Documentation تجویز کرتی ہے: پہلے سے طے شدہ طور پر، تمام ملکیت کے رشتوں کے لیے strong استعمال کریں۔ اگر آپ کو retain cycle سے بچنے کی ضرورت ہے — طے کریں کہ کون سا حوالہ کمزور ہونا چاہیے۔ عام طور پر یہ درجہ بندی میں الٹا حوالہ ہے (بچہ → والد)۔ Kotlin میں، java.lang.ref کا WeakReference اسی طرح کا کردار ادا کرتا ہے، جو کیشز اور observer پیٹرن کے لیے استعمال ہوتا ہے۔
Retain cycles کا پتہ لگانا پہلا قدم ہے۔ دوسرا انہیں صحیح طریقے سے ختم کرنا ہے۔ مضبوط حوالہ چکروں کو توڑنے کا بنیادی آلہ حوالوں میں سے ایک کو weak یا unowned سے بدلنا ہے۔ کوڑا کرکٹ جمع کرنے والی زبانوں میں، ہر رسائی سے پہلے دستی null جانچ کے ساتھ WeakReference اضافی طور پر استعمال ہوتا ہے۔
Swift اور Objective-C میں، سب سے عام اصلاح closures میں [weak self] شامل کرنا ہے۔ یہ اس بات کو یقینی بناتا ہے کہ closure آبجیکٹ کو اس کے ڈی ایلوکیٹ ہونے کے بعد نہیں رکھتا۔ Kotlin میں، اسی طرح کے مقاصد کے لیے WeakReference ریپر یا onDestroy میں واضح حوالہ صفائی استعمال ہوتی ہے۔
class NetworkService {
func fetchData(completion: @escaping (Data?) -> Void) {
// weak self کے ذریعے کیپچر — retain cycle ختم
URLSession.shared.dataTask(
with: URL(string: "https://api.example.com")!
) { [weak self] data, response, error in
guard let self else { return }
completion(data)
}.resume()
}
}
اس مثال میں، [weak self] اس بات کو یقینی بناتا ہے کہ NetworkService کو closure کے ذریعے اس کے ضروری نہ رہنے کے بعد نہیں رکھا جاتا۔ اگر درخواست مکمل ہونے سے پہلے self ڈی ایلوکیٹ ہو جاتا ہے — guard let self else { return } completion کو کال کیے بغیر closure سے باہر نکلتا ہے۔
Retain cycles کی تشخیص کے لیے، iOS کے لیے Instruments Leaks یا Android کے لیے Android Profiler + LeakCanary استعمال کریں۔ یہ اوزار درست برقرار رکھنے کا گراف دکھاتے ہیں اور اشارہ کرتے ہیں کہ کون سا مضبوط حوالہ آبجیکٹ کی آزادی کو روک رہا ہے۔ باقاعدہ میموری پروفائلنگ کسی بھی موبائل پروجیکٹ کے CI/CD پائپ لائن کا حصہ ہونی چاہیے۔
Swift اور Kotlin بنیادی طور پر مختلف میموری مینجمنٹ میکانزم استعمال کرتے ہیں، لیکن مضبوط حوالہ کا تصور دونوں میں موجود ہے۔ Swift retain count = 0 پر ہم آہنگ آزادی کے ساتھ ARC استعمال کرتا ہے۔ Kotlin ایک ٹریسنگ GC استعمال کرتا ہے جو ناقابل رسائی آبجیکٹ کو غیر متزامن طور پر صاف کرتا ہے۔
| پیرامیٹر | Swift (ARC) | Kotlin (JVM GC) |
|---|---|---|
| میکانزم | حوالہ گنتی (retain count) | رسائی کا سراغ لگانا (GC Roots) |
| آزادی | ہم آہنگ (کاؤنٹر صفر ہونے پر) | غیر متزامن (GC سائیکل سے) |
| Retain cycle | خودکار طور پر پتہ نہیں چلتا | GC پتہ لگا سکتا ہے، لیکن فوری طور پر نہیں |
| کمزور حوالہ | weak (خودکار صفر کرنا) | WeakReference (دستی جانچ) |
بنیادی عملی فرق: Swift میں، retain cycle ایک یقینی لیک ہے۔ Kotlin میں، GC چکر توڑ سکتا ہے اگر آبجیکٹ جڑ سے ناقابل رسائی ہوں، لیکن لیک شدہ آبجیکٹ کی زندگی غیر متوقع رہتی ہے۔ لہذا، دونوں زبانوں میں، بہترین حکمت عملی ڈیزائن کے مرحلے میں مضبوط حوالہ چکروں سے بچنا ہے۔
Swift کے لیے، مندوبین کے پیٹرن اور closures میں weak استعمال کریں۔ Kotlin کے لیے، WeakReference یا Lifecycle-aware اجزاء استعمال کریں جو مالک کے تباہ ہونے پر خودکار طور پر حوالے صاف کرتے ہیں۔ دونوں طریقوں میں، مقصد ایک ہی ہے — مضبوط حوالوں کو ختم کرنا جہاں وہ ایک نہ ٹوٹنے والی برقرار رکھنے کی زنجیر بناتے ہیں۔
اکثر پوچھے گئے سوالات
Strong Reference آبجیکٹ کے retain count کو بڑھاتا ہے اور جب تک حوالہ موجود ہے اس کی آزادی کو روکتا ہے۔ Weak Reference retain count کو تبدیل نہیں کرتا اور آبجیکٹ کے میموری سے ہٹائے جانے پر خودکار طور پر nil ہو جاتا ہے۔ مضبوط حوالے ملکیت کے لیے استعمال ہوتے ہیں، کمزور حوالے الٹے روابط اور مندوبین کے لیے۔
Retain cycle — ایک باہمی تالا ہے جس میں دو آبجیکٹ ایک دوسرے کو مضبوط حوالوں سے رکھتے ہیں۔ ان کا retain count کبھی صفر نہیں ہوتا، میموری آزاد نہیں ہوتی۔ اس سے میموری لیک ہوتی ہے: آبجیکٹ ہمیشہ کے لیے ہیپ میں رہتے ہیں، ایپلیکیشن زیادہ سے زیادہ وسائل استعمال کرتی ہے اور آخرکار OutOfMemory کے ساتھ کریش ہوتی ہے۔
Xcode سے Instruments Leaks استعمال کریں — Leaks ٹیمپلیٹ کے ساتھ پروفائلنگ چلائیں، ایپ میں ایک منظر نامہ انجام دیں اور لیک کے اشارے چیک کریں۔ درست تشخیص کے لیے، Cycles & Roots ٹیب پر جائیں — یہ باہمی مضبوط حوالوں کا گراف دکھاتا ہے جو ایک نہ ٹوٹنے والا چکر بناتے ہیں۔
Unowned اس وقت استعمال کرنا چاہیے جب بچے کے آبجیکٹ کی زندگی والد کی زندگی سے زیادہ نہ ہونے کی ضمانت ہو — مثال کے طور پر، کسی آبجیکٹ کو سختی سے متعین دائرہ کار میں باندھتے وقت۔ شک ہونے پر، Weak استعمال کریں، کیونکہ آزاد شدہ unowned حوالہ تک رسائی ایپلیکیشن کریش کا سبب بنتی ہے۔
بالواسطہ طور پر — ہاں۔ ARC میں ہر retain اور release ایک ایٹمی عمل ہے جس میں اوور ہیڈ ہے۔ چکروں میں بڑی تعداد میں آبجیکٹ کے ساتھ، یہ کارکردگی کو متاثر کر سکتا ہے۔ تاہم، بنیادی مسئلہ ARC کی رفتار نہیں ہے، بلکہ غلط طریقے سے منتخب کردہ حوالہ کی قسم کی وجہ سے میموری لیک ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں