Callback — यह क्या है, कॉलबैक फ़ंक्शन और यह कैसे काम करता है

लेखक: IT Sectr प्रकाशित: 2026-03-17 पढ़ने का समय: 11 मिनट

Callback एक फ़ंक्शन है जो किसी अन्य फ़ंक्शन में आर्गुमेंट के रूप में पास किया जाता है और एसिंक्रोनस ऑपरेशन पूरा होने के बाद निष्पादित होता है। मोबाइल डेवलपमेंट में, callback का उपयोग नेटवर्क अनुरोधों, डेटाबेस संचालन और एनिमेशन के परिणामों को संसाधित करने के लिए किया जाता है। Apple दस्तावेज़ीकरण (2025) के अनुसार, Swift में क्लोज़र callback का प्राथमिक रूप हैं और URLSession, GCD और Combine में उपयोग किए जाते हैं। Android में, callback इंटरफ़ेस, Kotlin लैम्ब्डा और ListenableFuture के माध्यम से कार्यान्वित किया जाता है।

मुख्य बिंदु

  • Callback — एसिंक्रोनस निष्पादन के लिए आर्गुमेंट के रूप में पास किया जाने वाला कॉलबैक फ़ंक्शन।
  • Swift callback के लिए @escaping कीवर्ड के साथ क्लोज़र का उपयोग करता है।
  • Kotlin callback के लिए लैम्ब्डा एक्सप्रेशन और उच्च-क्रम फ़ंक्शन लागू करता है।
  • Retain cycle — iOS पर callback में self को कैप्चर करने पर मेमोरी लीक।
  • Callback Hell — नेस्टेड callback की समस्या, जो async/await और कोरूटीन के माध्यम से हल होती है।

Callback क्या है?

Callback (कॉलबैक फ़ंक्शन) एक निष्पादन योग्य कोड है जो किसी अन्य फ़ंक्शन में पास किया जाता है और किसी विशिष्ट कार्रवाई के पूरा होने के बाद कॉल किया जाता है। मोबाइल डेवलपमेंट में, callback एसिंक्रोनस प्रोग्रामिंग का एक मूलभूत तंत्र है, जो मुख्य थ्रेड को ब्लॉक किए बिना नेटवर्क अनुरोधों, टाइमर, एनिमेशन और I/O संचालन के पूरा होने पर प्रतिक्रिया करने की अनुमति देता है। Swift और Kotlin callback बनाने के लिए अंतर्निहित सिंटैक्टिक निर्माण प्रदान करते हैं — क्रमशः क्लोज़र और लैम्ब्डा।

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 उसी थ्रेड में निष्पादित होता है, एसिंक्रोनस callback डिस्पैचर (iOS में DispatchQueue, Kotlin में Dispatchers) द्वारा निर्धारित थ्रेड में निष्पादित होता है।

iOS और Android में Callback कैसे काम करता है?

दोनों प्लेटफ़ॉर्म पर callback तंत्र एक ही सिद्धांत पर आधारित है: एक फ़ंक्शन प्रथम श्रेणी की वस्तु के रूप में पास किया जाता है और निष्पादन के क्षण तक संग्रहीत रहता है। हालांकि, विभिन्न भाषा प्रतिमानों के कारण कार्यान्वयन भिन्न होते हैं। iOS में, callback एक क्लोज़र है जो आसपास के संदर्भ से चर कैप्चर करता है। Android में, callback अक्सर अनाम वर्गों या Kotlin लैम्ब्डा एक्सप्रेशन के माध्यम से कार्यान्वित किया जाता है, जो FunctionalInterface में संकलित होते हैं।

iOS में Callback का जीवनचक्र

जब कोई एसिंक्रोनस फ़ंक्शन कॉल किया जाता है, तो क्लोज़र कैप्चर किए गए चर के साथ heap पर संग्रहीत होता है। जब ऑपरेशन पूरा हो जाता है, तो GCD या OperationQueue सिस्टम callback को उपयुक्त क्यू (मुख्य क्यू या बैकग्राउंड क्यू) में रखता है। निष्पादन के बाद, जब कोई मजबूत संदर्भ नहीं होता है तो callback मेमोरी से हटा दिया जाता है। कैप्चर लिस्ट ([weak self]) ऑब्जेक्ट को डीलोकेशन के बाद बनाए रखने से रोकती है। कैप्चर लिस्ट के बिना, retain cycle उत्पन्न होता है जहां ऑब्जेक्ट और callback एक-दूसरे को संदर्भित करते हैं।

swift
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 का जीवनचक्र

Android में, callback इंटरफ़ेस या लैम्ब्डा के माध्यम से पास किया जाता है। ExecutorService या कोरूटीन के माध्यम से एसिंक्रोनस ऑपरेशन निष्पादित करते समय, बैकग्राउंड कार्य पूरा होने तक callback मेमोरी में संग्रहीत रहता है। Kotlin लैम्ब्डा अनाम वर्गों में संकलित होते हैं जो बाहरी चर कैप्चर करते हैं। JVM में कमजोर संदर्भों की अनुपस्थिति में मैन्युअल प्रबंधन की आवश्यकता होती है: onDestroy() में callback को शून्य करना या Job.cancel() के माध्यम से कोरूटीन रद्द करना। ViewModel और LiveData इस समस्या को आर्किटेक्चरल घटक स्तर पर हल करते हैं।

kotlin
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) }
})

Swift और Kotlin में Callback सिंटैक्स

Callback सिंटैक्स भाषा की फ़ंक्शन को प्रथम श्रेणी की वस्तु के रूप में उपयोग करने की क्षमता से निर्धारित होता है। Swift में, क्लोज़र का स्वचालित आर्गुमेंट नाम ($0, $1) के साथ संक्षिप्त सिंटैक्स होता है। Kotlin में, लैम्ब्डा एकल आर्गुमेंट के लिए it का समर्थन करते हैं। अंतर चर कैप्चर (Swift में कैप्चर लिस्ट बनाम Kotlin में परिवर्तनीय संदर्भ) और टाइपिंग (Result बनाम Result) के प्रबंधन में प्रकट होते हैं।

Swift में Callback: क्लोज़र (closures)

Swift क्लोज़र कोड का एक स्व-निहित ब्लॉक है जिसे किसी अन्य फ़ंक्शन में पास और उपयोग किया जा सकता है। क्लोज़र वैश्विक (नामित), नेस्टेड और एक्सप्रेशन-स्तर के हो सकते हैं। @escaping उस क्लोज़र को चिह्नित करता है जो फ़ंक्शन के वापस लौटने के बाद निष्पादित होगा — यह एसिंक्रोनस callback के लिए अनिवार्य आवश्यकता है। @escaping के बिना, क्लोज़र केवल फ़ंक्शन बॉडी के अंदर ही निष्पादित किया जा सकता है। Trailing closure सिंटैक्स कोष्ठक के बाद क्लोज़र पास करने की अनुमति देता है: fetchData { result in ... }.

swift
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 उच्च-क्रम फ़ंक्शन का समर्थन करता है जो अन्य फ़ंक्शन को पैरामीटर के रूप में स्वीकार करते हैं। Callback Kotlin में (T) -> Unit या रिटर्न वैल्यू के लिए (T) -> R प्रकार के पैरामीटर के माध्यम से पास किया जाता है। Kotlin कोरूटीन के suspend फ़ंक्शन callback को अनुक्रमिक कोड से बदल देते हैं, लेकिन callback Java-संगत API और Android SDK (View.setOnClickListener, TextWatcher) में बना रहता है। Kotlin लैम्ब्डा स्वचालित रूप से val चर कैप्चर करते हैं, var चर में परिवर्तनशीलता रैपर की आवश्यकता होती है।

kotlin
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 cycles और Callback में मेमोरी लीक

Retain cycle एक ऐसी स्थिति है जहां दो ऑब्जेक्ट एक-दूसरे के लिए मजबूत संदर्भ रखते हैं, जो मेमोरी प्रबंधक को उन्हें मुक्त करने से रोकता है। Swift में, retain cycle तब उत्पन्न होता है जब viewController एक क्लोज़र कैप्चर करता है और क्लोज़र self को कैप्चर करता है। Kotlin/Java में, लीक तब होता है जब Activity एक इनर क्लास या लैम्ब्डा को लंबे समय तक चलने वाले बैकग्राउंड ऑपरेशन में पास करती है। WWDC सत्र 10216 (2024) के अनुसार, अनुचित क्लोज़र प्रबंधन iOS अनुप्रयोगों में मेमोरी लीक का तीसरा सबसे आम कारण है।

Swift में Retain cycles

Swift स्वचालित संदर्भ गणना (ARC) का उपयोग करता है, जो संदर्भ काउंटर शून्य होने पर ऑब्जेक्ट को मुक्त करता है। क्लोज़र में कैप्चर लिस्ट [weak self] या [unowned self] retain cycle को रोकती है। weak self एक वैकल्पिक संदर्भ बनाता है जो ऑब्जेक्ट के डीलोकेट होने पर nil हो जाता है। unowned self मानता है कि ऑब्जेक्ट क्लोज़र से अधिक समय तक जीवित रहता है — इस धारणा के उल्लंघन पर क्रैश होता है। सुरक्षित डिफ़ॉल्ट के रूप में weak self का उपयोग करने की अनुशंसा की जाती है।

swift
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 में मेमोरी लीक

Android में, callback लीक तब होता है जब Activity या Fragment किसी singleton घटक (जैसे EventBus या Service) में listener पास करता है। WeakReference गार्बेज कलेक्टर को Activity को मुक्त करने की अनुमति देता है भले ही उसका कमजोर संदर्भ हो। Lifecycle-aware घटक (LiveData, Flow) समस्या को स्वचालित रूप से हल करते हैं। Kotlin लैम्ब्डा जो Activity संदर्भ कैप्चर करते हैं, वे भी लीक का कारण बन सकते हैं: लैम्ब्डा implicitly this का संदर्भ संग्रहीत करता है।

kotlin
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 और इससे निपटने के तरीके

Callback Hell (जिसे Pyramid of Doom के नाम से भी जाना जाता है) एक ऐसी स्थिति है जहां कई नेस्टेड callback कोड की एक गहराई से नेस्टेड संरचना बनाते हैं, जिसे पढ़ना और डीबग करना कठिन होता है। प्रत्येक अगले चरण में पिछले चरण के पूरा होने की प्रतीक्षा करनी होती है, जिससे 5-10 स्तरों तक नेस्टिंग होती है। यह समस्या अनुक्रमिक एसिंक्रोनस संचालन के लिए विशिष्ट है: डेटा लोड करना → पार्स करना → DB में सहेजना → UI अपडेट करना।

Swift में समाधान: async/await

Swift 5.5 ने एसिंक्रोनस फ़ंक्शन (async/await) पेश किए, जो एसिंक्रोनस कोड को अनुक्रमिक रूप से लिखने की अनुमति देते हैं। AsyncSequence और AsyncStream callback-आधारित पुनरावृत्तियों को बदल देते हैं। Combine फ्रेमवर्क बिना नेस्टिंग के एसिंक्रोनस स्ट्रीम की रचना के लिए flatMap, merge, combineLatest जैसे ऑपरेटर प्रदान करता है। हालांकि, Objective-C API और async समर्थन के बिना तीसरे पक्ष की लाइब्रेरी के साथ काम करने के लिए callback आवश्यक बना हुआ है।

swift
// नेस्टेड 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 में समाधान: कोरूटीन और Flow

Kotlin कोरूटीन अनुक्रमिक निष्पादन के लिए callback को suspend फ़ंक्शन से बदल देते हैं। Flow map, flatMapConcat, combine जैसे ऑपरेटरों के साथ कोल्ड स्ट्रीम प्रदान करता है। CoroutineScope किसी घटक के नष्ट होने पर सभी चल रहे कोरूटीन को रद्द करने की अनुमति देता है। Room, Retrofit और अन्य Jetpack लाइब्रेरी में suspend फ़ंक्शन के लिए अंतर्निहित समर्थन है, जो मानक संचालन में callback की आवश्यकता को समाप्त करता है।

kotlin
// अनुक्रमिक 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 vs Delegate: क्या चुनें?

Callback और Delegate एसिंक्रोनस सूचना के दो दृष्टिकोण हैं, और चुनाव आर्किटेक्चरल आवश्यकताओं पर निर्भर करता है। Callback एकल परिणाम वाले एक बार के संचालन के लिए उपयुक्त है। Delegate विभिन्न विधि हस्ताक्षरों के साथ कई घटनाओं के लिए डिज़ाइन किया गया है। Apple कई विधियों वाले जटिल प्रोटोकॉल के लिए delegate की सिफारिश करता है, और एकल परिणाम वाले सरल क्लोज़र के लिए callback की। Android में, लैम्ब्डा समर्थन के कारण callback अधिकांश मामलों में delegate को बदल देता है।

Callback कब चुनें

Callback एकल परिणाम वाले संचालन के लिए इष्टतम है: नेटवर्क अनुरोध, फ़ाइल रीडिंग, पूर्णता ब्लॉक के साथ एनिमेशन। लाभ: संक्षिप्त सिंटैक्स, कोई अलग प्रोटोकॉल नहीं, प्रत्यक्ष संदर्भ कैप्चर। नुकसान: कई परिणामों (प्रगति, विराम, रद्द) के साथ जटिलता, एकाधिक भेजने की असंभवता (यदि callback एक से अधिक बार कॉल किया जा सकता है — publisher का उपयोग करें)।

Delegate कब चुनें

Delegate कई अनिवार्य और वैकल्पिक विधियों वाले प्रोटोकॉल के लिए उपयुक्त है: UITableViewDelegate, CLLocationManagerDelegate, Bluetooth कनेक्शन। लाभ: प्रत्येक विधि के लिए स्पष्ट टाइपिंग, प्रोटोकॉल के माध्यम से दस्तावेज़ीकरण, @objc optional के माध्यम से वैकल्पिक विधियों का समर्थन। नुकसान: बॉयलरप्लेट कोड, delegate के लिए कमजोर संदर्भ अनिवार्य (weak var delegate), संदर्भ कैप्चर में जटिलता।

अक्सर पूछे जाने वाले प्रश्न

Callback और उच्च-क्रम फ़ंक्शन में क्या अंतर है?

Callback उच्च-क्रम फ़ंक्शन का एक विशेष मामला है। उच्च-क्रम फ़ंक्शन किसी अन्य फ़ंक्शन को तर्क के रूप में स्वीकार करता है या उसे लौटाता है। Callback एक ऐसा फ़ंक्शन है जो विशेष रूप से ऑपरेशन पूरा होने के बाद एसिंक्रोनस निष्पादन के लिए पास किया जाता है। सभी callback उच्च-क्रम फ़ंक्शन के माध्यम से कार्यान्वित किए जाते हैं, लेकिन प्रत्येक उच्च-क्रम फ़ंक्शन callback नहीं है।

क्या callback को कई बार कॉल किया जा सकता है?

सम्मेलन के अनुसार, callback को ठीक एक बार कॉल किया जाना चाहिए — या तो success या failure। एक ही callback का एकाधिक कॉल डिज़ाइन त्रुटि माना जाता है। कई घटनाओं (प्रगति, डेटा स्ट्रीम) के लिए, Observable, Publisher या Flow का उपयोग करें — वे कई मान उत्सर्जन का समर्थन करते हैं। कुछ API इस नियम का उल्लंघन करते हैं, जिससे ढूंढने में कठिन बग होते हैं।

Swift में trailing closure क्या है?

Trailing closure Swift सिंटैक्टिक शुगर है जो फ़ंक्शन कॉल के कोष्ठक के बाद क्लोज़र पास करने की अनुमति देता है। यदि कोई फ़ंक्शन अंतिम तर्क के रूप में क्लोज़र लेता है, तो इसे कोष्ठक के बाहर रखा जा सकता है: fetchData { result in ... }। कई क्लोज़र के लिए, trailing closure केवल अंतिम पर लागू होता है; शेष कोष्ठक के अंदर नामित होते हैं। यह callback-आधारित API की पठनीयता में सुधार करता है।

Android में callback के साथ मेमोरी लीक से कैसे बचें?

लंबे समय तक जीवित रहने वाले श्रोताओं के लिए WeakReference का उपयोग करें, onDestroy() में Job.cancel() के माध्यम से कोरूटीन रद्द करें, स्वचालित रद्दीकरण के लिए lifecycleScope का उपयोग करें। ViewModel + LiveData/Flow आर्किटेक्चरल स्तर पर समस्या का समाधान करता है। स्थिर callback में Activity संदर्भ पास करने से बचें — Application context का उपयोग करें। Kotlin लैम्ब्डा this को अंतर्निहित रूप से कैप्चर करते हैं, मेमोरी प्रोफाइलर से जांच करें।

क्या async/await callback को पूरी तरह से बदल देगा?

Async/await अनुक्रमिक एसिंक्रोनस कोड के लिए callback को बदलता है, लेकिन event-driven आर्किटेक्चर के लिए नहीं। Callback सिस्टम API (View.OnClickListener, URLSession delegates), प्रगति callback और तीसरे पक्ष की लाइब्रेरी में बना रहता है। पिछड़ी संगतता के कारण पूर्ण प्रतिस्थापन असंभव है। आधुनिक रणनीति callback रैपर (Swift में continuation, Kotlin में suspendCancellableCoroutine) के साथ async/await का उपयोग करना है।

सारांश

  • Callback — कॉलबैक फ़ंक्शन जो ऑपरेशन पूरा होने के बाद एसिंक्रोनस निष्पादन के लिए तर्क के रूप में पास किया जाता है।
  • Swift @escaping, कैप्चर लिस्ट [weak self] और trailing closure सिंटैक्स के साथ क्लोज़र के माध्यम से callback लागू करता है।
  • Kotlin एसिंक्रोनसी के लिए लैम्ब्डा, उच्च-क्रम फ़ंक्शन और कोरूटीन suspend फ़ंक्शन का उपयोग करता है।
  • Retain cycle iOS में कैप्चर लिस्ट द्वारा रोका जाता है; Android में — WeakReference और lifecycle-aware घटकों द्वारा।
  • Callback Hell Swift में async/await और Kotlin में Flow के साथ कोरूटीन द्वारा हल किया जाता है।
  • Delegate कई विधियों वाले प्रोटोकॉल के लिए callback से बेहतर है; एक बार के संचालन के लिए callback।
  • सरल एसिंक्रोनस संचालन के लिए callback, अनुक्रमिक श्रृंखलाओं के लिए async/await, कई घटनाओं के लिए delegate का उपयोग करें।

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें