Callback ایک فنکشن ہے جو کسی دوسرے فنکشن میں بطور دلیل منتقل کیا جاتا ہے اور اسینکرو نس آپریشن مکمل ہونے کے بعد عمل میں لایا جاتا ہے۔ موبائل ڈیولپمنٹ میں، callback نیٹ ورک کی درخواستوں کے نتائج، ڈیٹا بیس آپریشنز اور اینیمیشنز پر کارروائی کے لیے استعمال ہوتا ہے۔ Apple دستاویزات (2025) کے مطابق، Swift میں closures callback کی بنیادی شکل ہیں اور URLSession، GCD اور Combine میں استعمال ہوتے ہیں۔ Android میں، callback انٹرفیس، Kotlin lambda اور ListenableFuture کے ذریعے لاگو کیا جاتا ہے۔
اہم نکات
Callback (کال بیک فنکشن) قابل عمل کوڈ ہے جو کسی دوسرے فنکشن میں منتقل کیا جاتا ہے اور کسی مخصوص عمل کے مکمل ہونے کے بعد بلایا جاتا ہے۔ موبائل ڈیولپمنٹ میں، callback اسینکرو نس پروگرامنگ کا ایک بنیادی طریقہ کار ہے، جو مرکزی تھریڈ کو روکے بغیر نیٹ ورک کی درخواستوں، ٹائمرز، اینیمیشنز اور I/O آپریشنز کی تکمیل پر ردعمل ظاہر کرنے کی اجازت دیتا ہے۔ Swift اور Kotlin callback بنانے کے لیے بلٹ ان نحوی تعمیرات فراہم کرتے ہیں — بالترتیب closures اور lambdas۔
ایک اعلیٰ ترتیب کا فنکشن دوسرے فنکشن کو پیرامیٹر کے طور پر قبول کرتا ہے اور اپنی مرکزی منطق پر عمل کرنے کے بعد اسے بلاتا ہے۔ کنٹرول کا بہاؤ callback کے ذریعے کالر کو واپس بھیج دیا جاتا ہے، اسی لیے یہ نام ہے۔ iOS میں، callback UIKit (UIView.animate اینیمیشنز)، Foundation (URLSession.dataTask) اور Combine (sink) میں استعمال ہوتا ہے۔ Android میں، callback View.OnClickListener، Retrofit Callback اور Room DAO میں استعمال ہوتا ہے۔ جدید APIs تیزی سے callback کو async/await یا coroutines سے بدل رہی ہیں، لیکن لیگیسی کوڈ اور نچلی سطح کی APIs کے ساتھ کام کرنے کے لیے callback کی سمجھ ضروری ہے۔
Callback ہم وقت (فنکشن کے اندر فوری طور پر بلایا جاتا ہے) اور بے وقت (بعد میں کسی دوسرے تھریڈ یا قطار سے بلایا جاتا ہے) ہو سکتا ہے۔ ہم وقت callback ترتیب دینے (موازنہ کرنے والے) اور مجموعوں کو عبور کرنے کے لیے استعمال ہوتے ہیں۔ بے وقت callback نیٹ ورک کی درخواستوں، فائل پڑھنے اور سینسرز کے ساتھ کام کرنے کے لیے استعمال ہوتے ہیں۔ تھریڈنگ کو سمجھنے کے لیے فرق اہم ہے: ہم وقت callback اسی تھریڈ میں عمل میں لایا جاتا ہے، بے وقت callback ڈسپیچر (iOS میں DispatchQueue، Kotlin میں Dispatchers) کے ذریعے متعین کردہ تھریڈ میں عمل میں لایا جاتا ہے۔
دونوں پلیٹ فارمز پر callback میکانزم ایک ہی اصول پر مبنی ہے: ایک فنکشن فرسٹ کلاس آبجیکٹ کے طور پر منتقل کیا جاتا ہے اور عملدرآمد کے لمحے تک ذخیرہ کیا جاتا ہے۔ تاہم، مختلف زبانوں کے نمونوں کی وجہ سے نفاذ مختلف ہوتا ہے۔ iOS میں، callback ایک closure ہے جو ارد گرد کے سیاق و سباق سے متغیرات کو کیپچر کرتا ہے۔ Android میں، callback اکثر گمنام کلاسز یا Kotlin lambda اظہارات کے ذریعے لاگو کیا جاتا ہے، جو FunctionalInterface میں مرتب ہوتے ہیں۔
جب کوئی اسینکرو نس فنکشن بلایا جاتا ہے، closure کیپچر کیے گئے متغیرات کے ساتھ ہیپ پر ذخیرہ ہوتا ہے۔ جب آپریشن مکمل ہو جاتا ہے، GCD یا OperationQueue سسٹم callback کو مناسب قطار (مرکزی قطار یا پس منظر کی قطار) میں رکھتا ہے۔ عملدرآمد کے بعد، جب کوئی مضبوط حوالہ نہیں ہوتا تو callback میموری سے ہٹا دیا جاتا ہے۔ کیپچر لسٹ ([weak self]) ڈی لوکیشن کے بعد آبجیکٹ کو برقرار رکھنے سے روکتی ہے۔ کیپچر لسٹ کے بغیر، retain cycle پیدا ہوتا ہے جہاں آبجیکٹ اور callback ایک دوسرے کا حوالہ دیتے ہیں۔
func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
completion(.success(data))
}
task.resume()
}
// [weak self] کے ساتھ استعمال
fetchData { [weak self] result in
guard let self else { return }
switch result {
case .success(let data):
self.updateUI(data)
case .failure(let error):
self.showError(error)
}
}
Android میں، callback انٹرفیس یا lambda کے ذریعے منتقل کیا جاتا ہے۔ ExecutorService یا coroutine کے ذریعے اسینکرو نس آپریشن انجام دیتے وقت، پس منظر کا کام مکمل ہونے تک callback میموری میں ذخیرہ رہتا ہے۔ Kotlin lambdas گمنام کلاسز میں مرتب ہوتے ہیں جو بیرونی متغیرات کو کیپچر کرتی ہیں۔ JVM میں کمزور حوالوں کی عدم موجودگی میں دستی انتظام کی ضرورت ہوتی ہے: onDestroy() میں callback کو کالعدم کرنا یا Job.cancel() کے ذریعے coroutines منسوخ کرنا۔ ViewModel اور LiveData اس مسئلے کو آرکیٹیکچرل جزو کی سطح پر حل کرتے ہیں۔
interface Callback<T> {
fun onSuccess(data: T)
fun onError(error: Throwable)
}
class Repository {
fun loadData(callback: Callback<List<User>>) {
thread {
try {
val result = api.fetchUsers()
runOnUiThread { callback.onSuccess(result) }
} catch (e: Exception) {
runOnUiThread { callback.onError(e) }
}
}
}
}
// lambda کے ساتھ استعمال
repository.loadData(object : Callback<List<User>> {
override fun onSuccess(data: List<User>) { showUsers(data) }
override fun onError(error: Throwable) { showError(error.message) }
})
Callback نحو زبان کی فنکشنز کو فرسٹ کلاس آبجیکٹ کے طور پر استعمال کرنے کی صلاحیت سے متعین ہوتا ہے۔ Swift میں، closures خودکار دلیل ناموں ($0, $1) کے ساتھ مختصر نحو رکھتے ہیں۔ Kotlin میں، lambdas ایک دلیل کے لیے it کو سپورٹ کرتے ہیں۔ فرق متغیر کیپچر (Swift میں کیپچر لسٹ بمقابلہ Kotlin میں قابل تبدیلی حوالہ جات) اور ٹائپنگ (Result
Swift closure کوڈ کا ایک خود مختار بلاک ہے جسے کسی دوسرے فنکشن میں منتقل اور استعمال کیا جا سکتا ہے۔ closures عالمی (نامزد)، nest کیے گئے اور اظہار کی سطح کے ہو سکتے ہیں۔ @escaping اس closure کو نشان زد کرتا ہے جو فنکشن کی واپسی کے بعد عمل میں لایا جائے گا — یہ اسینکرو نس callback کے لیے لازمی شرط ہے۔ @escaping کے بغیر، closure صرف فنکشن باڈی کے اندر ہی عمل میں لایا جا سکتا ہے۔ Trailing closure نحو قوسین کے بعد closure منتقل کرنے کی اجازت دیتا ہے: fetchData { result in ... }۔
typealias NetworkResult = (Result<[String: Any], Error>) -> Void
func performRequest(
url: URL,
then handler: @escaping NetworkResult
) {
let task = URLSession.shared.dataTask(with: url) { data, _, error in
handler(Result {
guard let json = try JSONSerialization.jsonObject(with: data)
else { throw NetworkError.invalidData }
return json as! [String: Any]
})
}
task.resume()
}
performRequest(url: url) { result in
switch result {
case .success(let json): process(json)
case .failure(let error): log(error.localizedDescription)
}
}
Kotlin اعلیٰ ترتیب کے فنکشنز کو سپورٹ کرتا ہے جو دوسرے فنکشنز کو پیرامیٹر کے طور پر قبول کرتے ہیں۔ Callback Kotlin میں (T) -> Unit قسم کے پیرامیٹر یا واپسی کی قدروں کے لیے (T) -> R کے ذریعے منتقل کیا جاتا ہے۔ Kotlin coroutines کے suspend فنکشنز callback کو ترتیبی کوڈ سے بدل دیتے ہیں، لیکن callback Java کے مطابق APIs اور Android SDK (View.setOnClickListener، TextWatcher) میں باقی رہتے ہیں۔ Kotlin lambdas خود بخود val متغیرات کو کیپچر کرتے ہیں، var متغیرات کو تغیر پذیری ریپرز کی ضرورت ہوتی ہے۔
fun <T, R> processWithCallback(
input: T,
transform: (T) -> R,
onResult: (R) -> Unit
) {
thread {
val result = transform(input)
runOnUiThread { onResult(result) }
}
}
// lambda کے ساتھ مثال
processWithCallback(
input = "Hello",
transform = { it.length },
onResult = { length ->
textView.text = "Length: $length"
}
)
Retain cycle ایک ایسی صورت حال ہے جہاں دو آبجیکٹ ایک دوسرے کے لیے مضبوط حوالہ جات رکھتے ہیں، جو میموری مینیجر کو انہیں جاری کرنے سے روکتا ہے۔ Swift میں، retain cycle اس وقت پیدا ہوتا ہے جب viewController ایک closure کیپچر کرتا ہے اور closure self کو کیپچر کرتا ہے۔ Kotlin/Java میں، لیک اس وقت ہوتی ہے جب Activity ایک اندرونی کلاس یا lambda کو طویل عرصے تک چلنے والے پس منظر کے آپریشن میں منتقل کرتی ہے۔ WWDC سیشن 10216 (2024) کے مطابق، نامناسب closure انتظام iOS ایپلیکیشنز میں میموری لیک کی تیسری سب سے عام وجہ ہے۔
Swift خودکار حوالہ گنتی (ARC) استعمال کرتا ہے، جو حوالہ کاؤنٹر صفر ہونے پر آبجیکٹ کو جاری کرتا ہے۔ closure میں کیپچر لسٹ [weak self] یا [unowned self] retain cycle کو روکتی ہے۔ weak self ایک اختیاری حوالہ بناتا ہے جو آبجیکٹ کے ڈی لوکیٹ ہونے پر nil ہو جاتا ہے۔ unowned self فرض کرتا ہے کہ آبجیکٹ closure سے زیادہ دیر زندہ رہتا ہے — اس مفروضے کی خلاف ورزی پر کریش ہوتا ہے۔ محفوظ ڈیفالٹ کے طور پر weak self استعمال کرنے کی سفارش کی جاتی ہے۔
class DataController {
var onDataUpdate: ((String) -> Void)?
func setupCallback() {
// Retain cycle!
onDataUpdate = { text in
self.process(text)
}
// [weak self] سے درست کیا گیا
onDataUpdate = { [weak self] text in
guard let self else { return }
self.process(text)
}
}
func process(_ input: String) { }
}
Android میں، callback لیک اس وقت ہوتی ہے جب Activity یا Fragment کسی singleton جزو (مثلاً EventBus یا Service) میں listener منتقل کرتا ہے۔ WeakReference کوڑا کرکٹ جمع کرنے والے کو Activity جاری کرنے کی اجازت دیتا ہے چاہے اس کا کمزور حوالہ موجود ہو۔ Lifecycle-aware اجزاء (LiveData، Flow) خود بخود مسئلہ حل کرتے ہیں۔ Kotlin lambdas جو Activity سیاق و سباق کو کیپچر کرتے ہیں وہ بھی لیک کا سبب بن سکتے ہیں: lambda واضح طور پر this کا حوالہ ذخیرہ کرتا ہے۔
class SafeCallbackManager {
private val listeners = mutableListOf<WeakReference<(String) -> Unit>>()
fun addListener(callback: (String) -> Unit) {
listeners.add(WeakReference(callback))
}
fun notifyAll(data: String) {
val iterator = listeners.iterator()
while (iterator.hasNext()) {
val ref = iterator.next().get()
if (ref != null) ref(data)
else iterator.remove()
}
}
}
// Fragment میں استعمال
manager.addListener { result ->
// WeakReference Fragment کو برقرار نہیں رکھتا
updateUI(result)
}
Callback Hell (جسے Pyramid of Doom بھی کہا جاتا ہے) ایک ایسی صورت حال ہے جہاں متعدد nest کیے گئے callback کوڈ کا گہرا nest کی ہوئی ساخت بناتے ہیں، جسے پڑھنا اور ڈیبگ کرنا مشکل ہوتا ہے۔ ہر بعد والے مرحلے میں پچھلے مرحلے کے مکمل ہونے کا انتظار کرنا پڑتا ہے، جس کے نتیجے میں 5-10 سطحوں کی nesting ہوتی ہے۔ یہ مسئلہ ترتیبی اسینکرو نس آپریشنز کے لیے خصوصیت رکھتا ہے: ڈیٹا لوڈ کرنا → پارس کرنا → DB میں محفوظ کرنا → UI اپ ڈیٹ کرنا۔
Swift 5.5 نے اسینکرو نس فنکشنز (async/await) متعارف کرائے، جو اسینکرو نس کوڈ کو ترتیبی طور پر لکھنے کی اجازت دیتے ہیں۔ AsyncSequence اور AsyncStream callback پر مبنی تکرار کو بدل دیتے ہیں۔ Combine فریم ورک nesting کے بغیر اسینکرو نس سٹریمز کی تشکیل کے لیے flatMap، merge، combineLatest جیسے آپریٹرز فراہم کرتا ہے۔ تاہم، Objective-C APIs اور async سپورٹ کے بغیر تیسرے فریق کی لائبریریوں کے ساتھ کام کرنے کے لیے callback ضروری رہتا ہے۔
// nest کیے گئے callback — Callback Hell
loginUser(credentials) { user in
fetchProfile(user.id) { profile in
downloadAvatar(profile.avatarUrl) { image in
cacheImage(image) { success in
updateUI(user, profile, image)
}
}
}
}
// async/await — حل
func loadUserExperience() async throws {
let user = try await loginUser(credentials)
let profile = try await fetchProfile(user.id)
let image = try await downloadAvatar(profile.avatarUrl)
try await cacheImage(image)
updateUI(user, profile, image)
}
Kotlin coroutines ترتیبی عملدرآمد کے لیے callback کو suspend فنکشنز سے بدل دیتے ہیں۔ Flow map، flatMapConcat، combine جیسے آپریٹرز کے ساتھ سرد سٹریمز فراہم کرتا ہے۔ CoroutineScope کسی جزو کے تباہ ہونے پر تمام چلنے والے coroutines کو منسوخ کرنے کی اجازت دیتا ہے۔ Room، Retrofit اور دیگر Jetpack لائبریریوں میں suspend فنکشنز کے لیے بلٹ ان سپورٹ ہے، جو معیاری آپریشنز میں callback کی ضرورت کو ختم کرتا ہے۔
// ترتیبی callback — Callback Hell
api.login(credentials) { user ->
api.fetchProfile(user.id) { profile ->
api.download(profile.avatarUrl) { bytes ->
file.save(bytes) { result ->
textView.text = result.toString()
}
}
}
}
// Coroutines — حل
suspend fun loadUserData() {
val user = withContext(Dispatchers.IO) { api.login(credentials) }
val profile = withContext(Dispatchers.IO) { api.fetchProfile(user.id) }
val bytes = withContext(Dispatchers.IO) { api.download(profile.avatarUrl) }
withContext(Dispatchers.IO) { file.save(bytes) }
textView.text = "Done"
}
Callback اور Delegate اسینکرو نس اطلاع کے دو طریقے ہیں، اور انتخاب آرکیٹیکچرل ضروریات پر منحصر ہے۔ Callback ایک نتیجہ والے ایک بار کے آپریشنز کے لیے موزوں ہے۔ Delegate مختلف طریقوں کے دستخطوں کے ساتھ متعدد واقعات کے لیے ڈیزائن کیا گیا ہے۔ Apple متعدد طریقوں والے پیچیدہ پروٹوکول کے لیے delegate اور ایک نتیجہ والے سادہ closures کے لیے callback تجویز کرتا ہے۔ Android میں، lambda سپورٹ کی وجہ سے زیادہ تر معاملات میں callback delegate کی جگہ لے لیتا ہے۔
Callback ایک نتیجہ والے آپریشنز کے لیے بہترین ہے: نیٹ ورک کی درخواست، فائل پڑھنا، تکمیل کے بلاک کے ساتھ اینیمیشن۔ فوائد: کمپیکٹ نحو، علیحدہ پروٹوکول کی ضرورت نہیں، براہ راست سیاق و سباق کیپچر۔ نقصانات: متعدد نتائج (پیش رفت، توقف، منسوخی) کے ساتھ پیچیدگی، متعدد بار بھیجنے کا عدم امکان (اگر callback ایک سے زیادہ بار بلایا جا سکتا ہے — publisher استعمال کریں)۔
Delegate متعدد لازمی اور اختیاری طریقوں والے پروٹوکول کے لیے موزوں ہے: UITableViewDelegate، CLLocationManagerDelegate، Bluetooth کنکشنز۔ فوائد: ہر طریقہ کی واضح ٹائپنگ، پروٹوکول کے ذریعے دستاویزات، @objc optional کے ذریعے اختیاری طریقوں کی حمایت۔ نقصانات: بوائلر پلیٹ کوڈ، delegate کے لیے کمزور حوالہ لازمی (weak var delegate)، سیاق و سباق کیپچر میں پیچیدگی۔
اکثر پوچھے گئے سوالات
Callback اعلیٰ ترتیب کے فنکشن کی ایک خاص صورت ہے۔ اعلیٰ ترتیب کا فنکشن کسی دوسرے فنکشن کو دلیل کے طور پر قبول کرتا ہے یا اسے واپس کرتا ہے۔ Callback ایک فنکشن ہے جو خاص طور پر آپریشن مکمل ہونے کے بعد اسینکرو نس عملدرآمد کے لیے منتقل کیا جاتا ہے۔ تمام callback اعلیٰ ترتیب کے فنکشنز کے ذریعے لاگو کیے جاتے ہیں، لیکن ہر اعلیٰ ترتیب کا فنکشن callback نہیں ہے۔
کنونشن کے مطابق، callback کو بالکل ایک بار بلایا جانا چاہیے — یا تو success یا failure۔ ایک ہی callback کا متعدد بار بلانا ڈیزائن کی غلطی سمجھا جاتا ہے۔ متعدد واقعات (پیش رفت، ڈیٹا سٹریم) کے لیے، Observable، Publisher یا Flow استعمال کریں — یہ متعدد اقدار کے اخراج کو سپورٹ کرتے ہیں۔ کچھ APIs اس اصول کی خلاف ورزی کرتی ہیں، جس سے ڈھونڈنے میں مشکل بگز پیدا ہوتے ہیں۔
Trailing closure Swift نحوی شوگر ہے جو فنکشن کال کے قوسین کے بعد closure منتقل کرنے کی اجازت دیتا ہے۔ اگر کوئی فنکشن آخری دلیل کے طور پر closure قبول کرتا ہے، تو اسے قوسین کے باہر رکھا جا سکتا ہے: fetchData { result in ... }۔ متعدد closures کے لیے، trailing closure صرف آخری پر لاگو ہوتا ہے؛ باقی قوسین کے اندر نامزد کیے جاتے ہیں۔ یہ callback پر مبنی APIs کی پڑھنے کی اہلیت کو بہتر بناتا ہے۔
طویل عرصے تک چلنے والے سننے والوں کے لیے WeakReference استعمال کریں، onDestroy() میں Job.cancel() کے ذریعے coroutines منسوخ کریں، خودکار منسوخی کے لیے lifecycleScope استعمال کریں۔ ViewModel + LiveData/Flow آرکیٹیکچرل سطح پر مسئلہ حل کرتا ہے۔ جامد callbacks میں Activity سیاق و سباق منتقل کرنے سے گریز کریں — Application context استعمال کریں۔ Kotlin lambdas واضح طور پر this کیپچر کرتے ہیں، میموری پروفائلر سے جانچ کریں۔
Async/await ترتیبی اسینکرو نس کوڈ کے لیے callback کو بدلتا ہے، لیکن واقعہ پر مبنی آرکیٹیکچر کے لیے نہیں۔ Callback سسٹم APIs (View.OnClickListener، URLSession delegates)، پیش رفت callback اور تیسرے فریق کی لائبریریوں میں باقی رہتا ہے۔ پچھلی مطابقت کی وجہ سے مکمل تبدیلی ناممکن ہے۔ جدید حکمت عملی callback ریپرز (Swift میں continuation، Kotlin میں suspendCancellableCoroutine) کے ساتھ async/await استعمال کرنا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں