Callback एक फ़ंक्शन है जो किसी अन्य फ़ंक्शन में आर्गुमेंट के रूप में पास किया जाता है और एसिंक्रोनस ऑपरेशन पूरा होने के बाद निष्पादित होता है। मोबाइल डेवलपमेंट में, callback का उपयोग नेटवर्क अनुरोधों, डेटाबेस संचालन और एनिमेशन के परिणामों को संसाधित करने के लिए किया जाता है। Apple दस्तावेज़ीकरण (2025) के अनुसार, Swift में क्लोज़र callback का प्राथमिक रूप हैं और URLSession, GCD और Combine में उपयोग किए जाते हैं। Android में, callback इंटरफ़ेस, Kotlin लैम्ब्डा और ListenableFuture के माध्यम से कार्यान्वित किया जाता है।
मुख्य बिंदु
Callback (कॉलबैक फ़ंक्शन) एक निष्पादन योग्य कोड है जो किसी अन्य फ़ंक्शन में पास किया जाता है और किसी विशिष्ट कार्रवाई के पूरा होने के बाद कॉल किया जाता है। मोबाइल डेवलपमेंट में, callback एसिंक्रोनस प्रोग्रामिंग का एक मूलभूत तंत्र है, जो मुख्य थ्रेड को ब्लॉक किए बिना नेटवर्क अनुरोधों, टाइमर, एनिमेशन और I/O संचालन के पूरा होने पर प्रतिक्रिया करने की अनुमति देता है। Swift और Kotlin callback बनाने के लिए अंतर्निहित सिंटैक्टिक निर्माण प्रदान करते हैं — क्रमशः क्लोज़र और लैम्ब्डा।
एक उच्च-क्रम फ़ंक्शन दूसरे फ़ंक्शन को पैरामीटर के रूप में स्वीकार करता है और अपने मुख्य तर्क को निष्पादित करने के बाद उसे कॉल करता है। नियंत्रण प्रवाह callback के माध्यम से कॉलर को वापस भेज दिया जाता है, इसलिए इसका नाम। iOS में, callback का उपयोग UIKit (UIView.animate एनिमेशन), Foundation (URLSession.dataTask) और Combine (sink) में किया जाता है। Android में, callback का उपयोग View.OnClickListener, Retrofit Callback और Room DAO में किया जाता है। आधुनिक API तेजी से callback को async/await या कोरूटीन से बदल रहे हैं, लेकिन लीगेसी कोड और निम्न-स्तरीय API के साथ काम करने के लिए callback की समझ आवश्यक है।
Callback सिंक्रोनस (फ़ंक्शन के अंदर तुरंत कॉल किया जाता है) और एसिंक्रोनस (बाद में किसी अन्य थ्रेड या क्यू से कॉल किया जाता है) हो सकता है। सिंक्रोनस callback का उपयोग सॉर्टिंग (कम्पेरेटर) और कलेक्शन ट्रैवर्सल के लिए किया जाता है। एसिंक्रोनस callback का उपयोग नेटवर्क अनुरोधों, फ़ाइल रीडिंग और सेंसर के साथ काम करने के लिए किया जाता है। थ्रेडिंग को समझने के लिए अंतर महत्वपूर्ण है: सिंक्रोनस callback उसी थ्रेड में निष्पादित होता है, एसिंक्रोनस callback डिस्पैचर (iOS में DispatchQueue, Kotlin में Dispatchers) द्वारा निर्धारित थ्रेड में निष्पादित होता है।
दोनों प्लेटफ़ॉर्म पर callback तंत्र एक ही सिद्धांत पर आधारित है: एक फ़ंक्शन प्रथम श्रेणी की वस्तु के रूप में पास किया जाता है और निष्पादन के क्षण तक संग्रहीत रहता है। हालांकि, विभिन्न भाषा प्रतिमानों के कारण कार्यान्वयन भिन्न होते हैं। iOS में, callback एक क्लोज़र है जो आसपास के संदर्भ से चर कैप्चर करता है। Android में, callback अक्सर अनाम वर्गों या Kotlin लैम्ब्डा एक्सप्रेशन के माध्यम से कार्यान्वित किया जाता है, जो FunctionalInterface में संकलित होते हैं।
जब कोई एसिंक्रोनस फ़ंक्शन कॉल किया जाता है, तो क्लोज़र कैप्चर किए गए चर के साथ heap पर संग्रहीत होता है। जब ऑपरेशन पूरा हो जाता है, तो 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 इंटरफ़ेस या लैम्ब्डा के माध्यम से पास किया जाता है। ExecutorService या कोरूटीन के माध्यम से एसिंक्रोनस ऑपरेशन निष्पादित करते समय, बैकग्राउंड कार्य पूरा होने तक callback मेमोरी में संग्रहीत रहता है। Kotlin लैम्ब्डा अनाम वर्गों में संकलित होते हैं जो बाहरी चर कैप्चर करते हैं। JVM में कमजोर संदर्भों की अनुपस्थिति में मैन्युअल प्रबंधन की आवश्यकता होती है: onDestroy() में callback को शून्य करना या Job.cancel() के माध्यम से कोरूटीन रद्द करना। 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) }
}
}
}
}
// लैम्ब्डा के साथ उपयोग
repository.loadData(object : Callback<List<User>> {
override fun onSuccess(data: List<User>) { showUsers(data) }
override fun onError(error: Throwable) { showError(error.message) }
})
Callback सिंटैक्स भाषा की फ़ंक्शन को प्रथम श्रेणी की वस्तु के रूप में उपयोग करने की क्षमता से निर्धारित होता है। Swift में, क्लोज़र का स्वचालित आर्गुमेंट नाम ($0, $1) के साथ संक्षिप्त सिंटैक्स होता है। Kotlin में, लैम्ब्डा एकल आर्गुमेंट के लिए it का समर्थन करते हैं। अंतर चर कैप्चर (Swift में कैप्चर लिस्ट बनाम Kotlin में परिवर्तनीय संदर्भ) और टाइपिंग (Result
Swift क्लोज़र कोड का एक स्व-निहित ब्लॉक है जिसे किसी अन्य फ़ंक्शन में पास और उपयोग किया जा सकता है। क्लोज़र वैश्विक (नामित), नेस्टेड और एक्सप्रेशन-स्तर के हो सकते हैं। @escaping उस क्लोज़र को चिह्नित करता है जो फ़ंक्शन के वापस लौटने के बाद निष्पादित होगा — यह एसिंक्रोनस callback के लिए अनिवार्य आवश्यकता है। @escaping के बिना, क्लोज़र केवल फ़ंक्शन बॉडी के अंदर ही निष्पादित किया जा सकता है। Trailing 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 कोरूटीन के suspend फ़ंक्शन callback को अनुक्रमिक कोड से बदल देते हैं, लेकिन callback Java-संगत API और Android SDK (View.setOnClickListener, TextWatcher) में बना रहता है। Kotlin लैम्ब्डा स्वचालित रूप से val चर कैप्चर करते हैं, var चर में परिवर्तनशीलता रैपर की आवश्यकता होती है।
fun <T, R> processWithCallback(
input: T,
transform: (T) -> R,
onResult: (R) -> Unit
) {
thread {
val result = transform(input)
runOnUiThread { onResult(result) }
}
}
// लैम्ब्डा के साथ उदाहरण
processWithCallback(
input = "Hello",
transform = { it.length },
onResult = { length ->
textView.text = "Length: $length"
}
)
Retain cycle एक ऐसी स्थिति है जहां दो ऑब्जेक्ट एक-दूसरे के लिए मजबूत संदर्भ रखते हैं, जो मेमोरी प्रबंधक को उन्हें मुक्त करने से रोकता है। Swift में, retain cycle तब उत्पन्न होता है जब viewController एक क्लोज़र कैप्चर करता है और क्लोज़र self को कैप्चर करता है। Kotlin/Java में, लीक तब होता है जब Activity एक इनर क्लास या लैम्ब्डा को लंबे समय तक चलने वाले बैकग्राउंड ऑपरेशन में पास करती है। WWDC सत्र 10216 (2024) के अनुसार, अनुचित क्लोज़र प्रबंधन iOS अनुप्रयोगों में मेमोरी लीक का तीसरा सबसे आम कारण है।
Swift स्वचालित संदर्भ गणना (ARC) का उपयोग करता है, जो संदर्भ काउंटर शून्य होने पर ऑब्जेक्ट को मुक्त करता है। क्लोज़र में कैप्चर लिस्ट [weak self] या [unowned self] retain cycle को रोकती है। weak self एक वैकल्पिक संदर्भ बनाता है जो ऑब्जेक्ट के डीलोकेट होने पर nil हो जाता है। unowned self मानता है कि ऑब्जेक्ट क्लोज़र से अधिक समय तक जीवित रहता है — इस धारणा के उल्लंघन पर क्रैश होता है। सुरक्षित डिफ़ॉल्ट के रूप में 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 लैम्ब्डा जो Activity संदर्भ कैप्चर करते हैं, वे भी लीक का कारण बन सकते हैं: लैम्ब्डा implicitly 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 के नाम से भी जाना जाता है) एक ऐसी स्थिति है जहां कई नेस्टेड callback कोड की एक गहराई से नेस्टेड संरचना बनाते हैं, जिसे पढ़ना और डीबग करना कठिन होता है। प्रत्येक अगले चरण में पिछले चरण के पूरा होने की प्रतीक्षा करनी होती है, जिससे 5-10 स्तरों तक नेस्टिंग होती है। यह समस्या अनुक्रमिक एसिंक्रोनस संचालन के लिए विशिष्ट है: डेटा लोड करना → पार्स करना → DB में सहेजना → UI अपडेट करना।
Swift 5.5 ने एसिंक्रोनस फ़ंक्शन (async/await) पेश किए, जो एसिंक्रोनस कोड को अनुक्रमिक रूप से लिखने की अनुमति देते हैं। AsyncSequence और AsyncStream callback-आधारित पुनरावृत्तियों को बदल देते हैं। Combine फ्रेमवर्क बिना नेस्टिंग के एसिंक्रोनस स्ट्रीम की रचना के लिए flatMap, merge, combineLatest जैसे ऑपरेटर प्रदान करता है। हालांकि, Objective-C API और async समर्थन के बिना तीसरे पक्ष की लाइब्रेरी के साथ काम करने के लिए callback आवश्यक बना हुआ है।
// नेस्टेड 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 कोरूटीन अनुक्रमिक निष्पादन के लिए callback को suspend फ़ंक्शन से बदल देते हैं। Flow map, flatMapConcat, combine जैसे ऑपरेटरों के साथ कोल्ड स्ट्रीम प्रदान करता है। CoroutineScope किसी घटक के नष्ट होने पर सभी चल रहे कोरूटीन को रद्द करने की अनुमति देता है। 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()
}
}
}
}
// कोरूटीन — समाधान
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 की सिफारिश करता है, और एकल परिणाम वाले सरल क्लोज़र के लिए callback की। Android में, लैम्ब्डा समर्थन के कारण 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 का उपयोग करें — वे कई मान उत्सर्जन का समर्थन करते हैं। कुछ API इस नियम का उल्लंघन करते हैं, जिससे ढूंढने में कठिन बग होते हैं।
Trailing closure Swift सिंटैक्टिक शुगर है जो फ़ंक्शन कॉल के कोष्ठक के बाद क्लोज़र पास करने की अनुमति देता है। यदि कोई फ़ंक्शन अंतिम तर्क के रूप में क्लोज़र लेता है, तो इसे कोष्ठक के बाहर रखा जा सकता है: fetchData { result in ... }। कई क्लोज़र के लिए, trailing closure केवल अंतिम पर लागू होता है; शेष कोष्ठक के अंदर नामित होते हैं। यह callback-आधारित API की पठनीयता में सुधार करता है।
लंबे समय तक जीवित रहने वाले श्रोताओं के लिए WeakReference का उपयोग करें, onDestroy() में Job.cancel() के माध्यम से कोरूटीन रद्द करें, स्वचालित रद्दीकरण के लिए lifecycleScope का उपयोग करें। ViewModel + LiveData/Flow आर्किटेक्चरल स्तर पर समस्या का समाधान करता है। स्थिर callback में Activity संदर्भ पास करने से बचें — Application context का उपयोग करें। Kotlin लैम्ब्डा this को अंतर्निहित रूप से कैप्चर करते हैं, मेमोरी प्रोफाइलर से जांच करें।
Async/await अनुक्रमिक एसिंक्रोनस कोड के लिए callback को बदलता है, लेकिन event-driven आर्किटेक्चर के लिए नहीं। Callback सिस्टम API (View.OnClickListener, URLSession delegates), प्रगति callback और तीसरे पक्ष की लाइब्रेरी में बना रहता है। पिछड़ी संगतता के कारण पूर्ण प्रतिस्थापन असंभव है। आधुनिक रणनीति callback रैपर (Swift में continuation, Kotlin में suspendCancellableCoroutine) के साथ async/await का उपयोग करना है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें