Actor ایک قسم ہے جو Swift 5.5+ میں متعارف کرائی گئی ہے جو زبان کی سطح پر ڈیٹا ریس کے مسئلے کو حل کرتی ہے۔ دستی لاکس اور DispatchQueue قطاروں کے برعکس، actor خود بخود اپنی حالت کو الگ کرتا ہے اور اس تک رسائی کو ہم آہنگ کرتا ہے۔ اس کا مطلب ہے کہ دو تھریڈز بیک وقت actor قسم کی ایک ہی پراپرٹی کو تبدیل نہیں کر سکتے، جس سے ڈیویلپر کی طرف سے اضافی کوشش کے بغیر ریس کنڈیشن ختم ہو جاتی ہے۔ یہ طریقہ کار actor-آئسولیشن کے تصور پر مبنی ہے، جہاں کمپائلر actor کی پراپرٹیز اور طریقوں تک رسائی کو ٹریک کرتا ہے۔ Apple، 2025 کے مطابق، actor ماڈل Swift کے کنکرنسی سسٹم کا ایک بنیادی حصہ ہے۔
اہم نکات
Actor ایک حوالہ جاتی قسم ہے، کلاس کی طرح، لیکن ڈیٹا ریس کے خلاف خودکار تحفظ کے ساتھ۔ یہ Swift 5.5 میں async/await اور Task کے ساتھ کنکرنسی سسٹم کے حصے کے طور پر متعارف کرایا گیا تھا۔ Actor اس بات کی ضمانت دیتا ہے کہ اس کی قابل تبدیلی حالت کو واضح ہم آہنگی کے بغیر مختلف تھریڈز سے بیک وقت کبھی نہیں پڑھا یا لکھا جائے گا۔
ایک actor اعلان کرنے کے لیے، actor کلیدی لفظ استعمال کیا جاتا ہے جس کے بعد اس کے ممبرز کے ساتھ گھنگریالے بریکٹ آتے ہیں۔ نحوی طور پر، actor کلاس سے ملتا جلتا ہے، لیکن اس کا رویہ یکسر مختلف ہے۔
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
self.balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
کمپائلر خود بخود تمام actor پراپرٹیز اور طریقوں کو الگ کرتا ہے تاکہ وہ صرف actor سیاق و سباق کے اندر قابل رسائی ہوں۔ actor کے باہر سے balance تک رسائی حاصل کرنے کی کوشش کرتے وقت، کمپائلر ایک خرابی پیدا کرے گا اگر کال کو async کے طور پر نشان زد نہ کیا گیا ہو۔
ڈیٹا آئسولیشن actor کا کلیدی تصور ہے۔ ایک actor actor ایگزیکیوٹر میکانزم کے ذریعے اپنی حالت تک باہمی خصوصی رسائی کی ضمانت دیتا ہے۔ ہر actor کا اپنا ایگزیکیوٹر ہوتا ہے جو اس کے الگ تھلگ ممبرز تک تمام رسائی کو ترتیب وار پروسیس کرتا ہے۔
جب actor کے باہر کا کوڈ اس کا طریقہ کال کرتا ہے، تو کال actor ایگزیکیوٹر قطار میں رکھی جاتی ہے۔ Actor ایک وقت میں صرف ایک کام انجام دیتا ہے، ریس کی عدم موجودگی کی ضمانت دیتا ہے۔ اگر دو تھریڈز بیک وقت deposit کال کرتے ہیں، تو دوسری کال پہلی کے مکمل ہونے کا انتظار کرتی ہے۔
let account = BankAccount(initialBalance: 1000.0)
// غیر مطابقت پذیر کال — actor کے باہر سے درکار
await account.deposit(amount: 500.0)
let currentBalance = await account.getBalance()
actor طریقے کی ہر کال کے لیے await ضروری ہے کیونکہ actor کسی دوسرے کام میں مصروف ہو سکتا ہے۔ یہ کوئی بگ نہیں بلکہ ایک شعوری ڈیزائن ہے جو ریس کو روکتا ہے۔ Swift واضح طور پر actor پراپرٹیز کے گیٹرز اور سیٹرز کو async بناتا ہے، لہٰذا پراپرٹی پڑھنے کے لیے بھی await کی ضرورت ہوتی ہے۔
Actor اور کلاس دونوں حوالہ جاتی اقسام ہیں، لیکن ملٹی تھریڈڈ ماحول میں ان کا رویہ یکسر مختلف ہے۔ کلاس ریس کے خلاف کوئی خودکار تحفظ فراہم نہیں کرتی، جبکہ actor اسے ٹائپ سسٹم کے ذریعے کمپائلر کی سطح پر شامل کرتا ہے۔
| خصوصیت | Actor | کلاس |
|---|---|---|
| ریس تحفظ | خودکار، کمپائلر کی سطح پر | دستی ہم آہنگی درکار ہے |
| پراپرٹی تک رسائی | صرف باہر سے await کے ذریعے | براہ راست، ہم آہنگی کے بغیر |
| وراثت | صرف دوسرے actors سے | معیاری کلاس پر مبنی |
| پروٹوکول مطابقت | پروٹوکول کے مطابق ہو سکتا ہے | معیاری |
| کارکردگی | آئسولیشن کے ساتھ کم اوورہیڈ | ہم آہنگی کے بغیر تیز |
ایک actor صرف دوسرے actor سے وراثت پا سکتا ہے اور کلاس سے وراثت نہیں پا سکتا۔ یہ جان بوجھ کر کیا گیا ہے کیونکہ کلاس میں actor آئسولیشن میکانزم کا فقدان ہے، اور اقسام کو ملانے سے حفاظتی ضمانتیں ٹوٹ جائیں گی۔
actor SavingsAccount: BankAccount {
func applyInterest(rate: Double) {
let interest = balance * rate
balance += interest
}
}
غیر مطابقت پذیر کالز بیرونی کوڈ سے actor کے ساتھ تعامل کا طریقہ کار ہیں۔ چونکہ actor اپنی حالت کو الگ کرتا ہے، باہر سے اس کے ممبرز تک کسی بھی رسائی کے لیے await کی ضرورت ہوتی ہے۔ یہ Swift کو اس بات کی ضمانت دینے کی اجازت دیتا ہے کہ کال کرنے والا کوڈ تھریڈ کو بلاک نہیں کرتا اور actor دوسری درخواستوں پر کارروائی کر سکتا ہے۔
اعلان کردہ actor اقسام کے علاوہ، Swift عالمی actors کو سپورٹ کرتا ہے — @MainActor وصف، جو کلاسز، پراپرٹیز یا طریقوں کو مرکزی تھریڈ پر قابل عمل قرار دیتا ہے۔ یہ iOS ایپلیکیشنز میں UI کوڈ کے لیے خاص طور پر مفید ہے۔
@MainActor
class ViewModel: ObservableObject {
@Published var title: String = ""
func updateTitle() {
// یہ کوڈ مرکزی تھریڈ پر چلنے کی ضمانت ہے
title = "New Title"
}
}
@MainActor کا استعمال دستی طور پر DispatchQueue.main.async کال کرنے کی ضرورت کو ختم کرتا ہے، کوڈ کو صاف اور محفوظ بناتا ہے۔ کمپائلر اس بات کو یقینی بناتا ہے کہ مرکزی تھریڈ میں سوئچنگ درست طریقے سے ہو۔
Nonisolated ایک کلیدی لفظ ہے جو actor کے کسی طریقے یا حسابی پراپرٹی کو غیر الگ تھلگ قرار دینے کی اجازت دیتا ہے۔ ایسے ممبرز actor کی الگ تھلگ حالت تک رسائی نہیں رکھتے، لیکن actor کے باہر سے await کے بغیر بلائے جا سکتے ہیں۔
Nonisolated طریقے ان حسابوں کے لیے مفید ہیں جو actor کی قابل تبدیلی حالت پر منحصر نہیں ہوتے۔ مثال کے طور پر، formatBalance طریقہ براہ راست balance تک رسائی حاصل نہیں کرتا، بلکہ صرف منتقل کردہ قدر کو فارمیٹ کرتا ہے — ایسا طریقہ nonisolated بنانا محفوظ ہے۔
actor BankAccount {
private var balance: Double = 0
nonisolated func formatBalance(amount: Double) -> String {
return "$\(amount)"
}
}
Nonisolated ممبرز ہم آہنگی سے عمل میں آتے ہیں اور await کی ضرورت نہیں ہوتی۔ تاہم، وہ actor کی الگ تھلگ پراپرٹیز براہ راست نہیں پڑھ سکتے۔ اگر کسی nonisolated طریقے کو actor سے قدر کی ضرورت ہو تو اسے پیرامیٹر کے طور پر منتقل کیا جانا چاہیے۔
Reentrancy ایک میکانزم ہے جو غیر مطابقت پذیر کال کے انتظار کے دوران actor میں دوبارہ داخلے کی اجازت دیتا ہے۔ Reentrancy کے بغیر، actor ہمیشہ کے لیے ڈیڈلاک ہو سکتا ہے اگر اس کا ایک طریقہ دوسرے کا انتظار کرے جو بدلے میں پہلے کا انتظار کرے۔
جب actor کے اندر کا کوڈ await انجام دیتا ہے، actor موجودہ کام کو معطل کرتا ہے اور قطار میں موجود کسی اور کام پر کارروائی کر سکتا ہے۔ await مکمل ہونے کے بعد، کام دوبارہ شروع ہو جاتا ہے۔ یہ ڈیڈلاک کو روکتا ہے لیکن احتیاط کی ضرورت ہے: await پوائنٹس کے درمیان actor کی حالت تبدیل ہو سکتی ہے۔
actor DataProcessor {
var cache: [Int: String] = [:]
func process(id: Int) async -> String {
if let cached = cache[id] {
return cached
}
// await — دوبارہ داخلے کا نقطہ
let result = await fetchData(id: id)
// await کے بعد کیش تبدیل ہو سکتی ہے — دوبارہ چیک کریں
cache[id] = result
return result
}
}
ڈیویلپرز کو دوبارہ داخلے کو مدنظر رکھنا چاہیے اور await پوائنٹس کے بعد actor کی حالت چیک کرنی چاہیے۔ ایک عام غلطی یہ فرض کرنا ہے کہ actor آئسولیشن غیر مطابقت پذیر معطلی پوائنٹس کے ذریعے برقرار رہتی ہے۔ عملی طور پر، await اور اگلے اسٹیٹمنٹ کے درمیان، حالت توقع سے مختلف ہو سکتی ہے۔
اکثر پوچھے جانے والے سوالات
Actor خود بخود اپنی حالت کو ڈیٹا ریس سے الگ کرتا ہے، بیرونی رسائی کے لیے await کی ضرورت ہوتی ہے۔ کلاس اس طرح کا تحفظ فراہم نہیں کرتی — ڈیویلپر لاکس یا قطاروں کے ذریعے ہم آہنگی کا ذمہ دار ہے۔ Actor صرف actor سے وراثت پاتا ہے، کلاس کلاس سے وراثت پاتی ہے۔
ہاں، ایک actor دوسرے actor سے وراثت پا سکتا ہے۔ ذیلی طبقہ والدین کی تمام الگ تھلگ پراپرٹیز اور طریقے حاصل کرتا ہے۔ Actor کلاس سے وراثت نہیں پا سکتا کیونکہ کلاسز میں کمپائلر کی سطح پر actor آئسولیشن میکانزم کا فقدان ہے۔
actor-isolated سیاق و سباق کوڈ کا ایک علاقہ ہے جہاں actor کی قابل تبدیلی حالت تک براہ راست رسائی کی اجازت ہے۔ الگ تھلگ قرار دیے گئے (بطور ڈیفالٹ) actor طریقوں کے اندر، await کے بغیر پراپرٹیز پڑھی اور لکھی جا سکتی ہیں۔ کمپائلر آئسولیشن کی حدود چیک کرتا ہے۔
Actor سے ڈیٹا async طریقوں کے ذریعے منتقل کیا جاتا ہے جو Sendable اقسام لوٹاتے ہیں، یا nonisolated طریقوں کے ذریعے جو پیرامیٹر کے طور پر قدریں قبول کرتے ہیں۔ ایک async پراپرٹی بھی بنائی جا سکتی ہے جو Sendable ساخت کے طور پر actor کی حالت کا سنیپ شاٹ لوٹاتی ہے۔
ہاں، actor پروٹوکول کے مطابق ہو سکتا ہے۔ اگر کسی پروٹوکول میں الگ تھلگ تقاضے (actor-isolated) ہوں تو وہ خود بخود actor سے الگ تھلگ ہو جاتے ہیں۔ پروٹوکول میں غیر مطابقت پذیر طریقوں کے لیے، isolated مارکر کا استعمال کرتے ہوئے یہ بتایا جا سکتا ہے کہ انہیں کسی مخصوص actor پر کال کیا جانا چاہیے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں