Error Propagation ایک طریقہ کار ہے جو غلطی کو وقوع کے مقام سے کال اسٹیک میں اوپر ہینڈلر تک پھیلاتا ہے۔ جب کوئی فنکشن خود غلطی کو ہینڈل نہیں کر سکتا، تو وہ اسے استثنیٰ (exception)، throws اعلان یا Return Type کے ذریعے کال کرنے والے فریق کو منتقل کرتا ہے۔ موبائل ایپلیکیشنز کے استحکام کے لیے propagation کا درست نفاذ بہت اہم ہے: غیر ہینڈل یا غلط طریقے سے منتقل کردہ غلطیاں کریش کا سبب بنتی ہیں۔ Apple Swift Documentation (2026) کے مطابق، Swift میں throws کے ذریعے خودکار propagation بغیر بوائلر پلیٹ کوڈ کے کسی بھی سطح پر غلطی منتقل کرنے کی اجازت دیتا ہے۔
اہم نکات
Error Propagation (غلطی کا پھیلاؤ) غلطی آبجیکٹ کو اس فنکشن سے جہاں یہ واقع ہوا کال چین میں اوپر قریب ترین موزوں ہینڈلر تک منتقل کرنے کا عمل ہے۔ کال اسٹیک کا تصور کریں: ViewController ViewModel کو کال کرتا ہے، ViewModel Repository کو کال کرتا ہے، Repository API کو کال کرتا ہے۔ اگر API نیٹ ورک کی غلطی لوٹاتا ہے، تو اسے Repository اور ViewModel کے ذریعے ViewController تک جانا ہوگا، جو صارف کو پیغام دکھائے گا۔ ہر درمیانی فنکشن فیصلہ کرتا ہے: غلطی کو ہینڈل کریں یا آگے منتقل کریں (propagate)۔
Propagation کے دو طریقے ہیں: خودکار اور دستی۔ خودکار طریقے (Swift throws، Java چیکڈ استثنیات) میں کمپائلر ڈویلپر کو یا تو غلطی ہینڈل کرنے یا دستخط میں propagation اعلان کرنے پر مجبور کرتا ہے۔ دستی طریقے (Result Type، Kotlin Try) میں غلطی ایک قدر کے طور پر منتقل کی جاتی ہے — ڈویلپر واضح طور پر غلطی کو منتقل کرنے یا تبدیل کرنے کے لیے کوڈ لکھتا ہے۔ Kotlin Result Docs (2026) کے مطابق، Kotlin میں Result<T> براہ راست فنکشن حدود کے پار propagation کے لیے ڈیزائن نہیں کیا گیا — اسے ہر سطح پر تبدیل یا ہینڈل کرنے کی ضرورت ہوتی ہے، جو propagation کو زیادہ باشعور لیکن زیادہ لفاظی والا بناتا ہے۔
طریقے کا انتخاب ایپلیکیشن آرکیٹیکچر اور زبان پر منحصر ہے۔ Swift میں throws کے ذریعے خودکار propagation غالب ہے، Kotlin میں استثنیات (غیر متوقع غلطیوں کے لیے) اور Result جیسے کنٹینر (متوقع غلطیوں کے لیے) کا مرکب استعمال ہوتا ہے۔ یہ سمجھنا ضروری ہے: propagation کوئی مقصد نہیں، بلکہ ایک ضرورت ہے۔ ایک مثالی آرکیٹیکچر propagation کی گہرائی کو کم کرتا ہے، غلطیوں کو کم سے کم ممکنہ سطح پر ہینڈل کرتا ہے جہاں فیصلہ کرنے کے لیے کافی سیاق و سباق ہو۔
Swift میں، throws کے ذریعے propagation خودکار ہے: اگر فنکشن A (throws کے ساتھ) فنکشن B (throws کے ساتھ) کو کال کرتا ہے، اور A do-catch میں B کی غلطی کو ہینڈل نہیں کرتا، تو غلطی خود بخود A کے کالر کو منتقل ہو جاتی ہے۔ یہ Java چیکڈ استثنیات کے عام بوائلر پلیٹ کوڈ کو ختم کرتا ہے، جہاں زنجیر کے ہر طریقہ میں throws اعلان کرنا ضروری ہوتا ہے۔ Swift اصول استعمال کرتا ہے «زنجیر میں ایک throws فنکشن = پوری زنجیر throws بن جاتی ہے، اگر درمیانی سطحوں پر ہینڈل نہ کیا جائے»۔
struct UserRepository {
func fetchUser(id: Int) throws -> User {
let data = try networkService.request(path: "/users/\(id)")
return try parseUser(from: data)
}
}
class UserViewModel {
let repo = UserRepository()
func loadUser(id: Int) throws -> User {
return try repo.fetchUser(id: id)
}
}
// ViewController — حتمی ہینڈلر
func onButtonTap() {
let vm = UserViewModel()
do {
let user = try vm.loadUser(id: 42)
updateUI(user)
} catch {
showError("صارف لوڈ کرنے میں ناکام")
}
}
Propagation زنجیر: networkService.request -> fetchUser -> loadUser -> onButtonTap۔ ہر درمیانی فنکشن throws سے نشان زد ہے اور do-catch پر مشتمل نہیں ہے — غلطی خود بخود اوپر منتقل ہوتی ہے۔ ViewController onButtonTap do-catch کے ساتھ آخری ہینڈلر ہے۔ اگر ViewModel غلطی کو تبدیل کرنے (دوسری قسم میں لپیٹنے) کا فیصلہ کرتا، تو وہ do-catch اور نیا throw استعمال کر سکتا تھا۔ خودکار propagation کوڈ کو کم کرتا ہے: Repository کو یہ جاننے کی ضرورت نہیں ہے کہ غلطی کو کیسے ہینڈل کرنا ہے — یہ ViewController کی ذمہ داری ہے، جس کے پاس صارف کو پیغام دکھانے کے لیے UI تک رسائی ہے۔
Kotlin میں، استثنیات کے ذریعے propagation کے لیے دستخط میں throws اعلان کی ضرورت نہیں ہے (تمام استثنیات ان چیکڈ ہیں)۔ استثنیٰ خود بخود اسٹیک میں اوپر چڑھتی ہے جب تک کہ try-catch سے نہ مل جائے۔ تاہم، دستخط میں throws کی عدم موجودگی propagation کو مضمر بنا دیتی ہے: ڈویلپر فنکشن کے دستخط سے نہیں دیکھ سکتا کہ یہ استثنیٰ پھینک سکتا ہے۔ یہ ایک ساتھ پلس (کم بوائلر پلیٹ) اور مائنس (ہینڈل کرنا بھولنا آسان) ہے۔ Kotlin اس مسئلے کو کنونشنز اور آرکیٹیکچرل پیٹرن کے ذریعے حل کرتا ہے، نہ کہ زبان کے ذریعے۔
class UserRepository(
private val api: ApiService,
private val db: Database
) {
suspend fun getUser(id: String): User {
return try {
api.fetchUser(id)
} catch (e: IOException) {
db.getCachedUser(id) ?: throw AppException("User unavailable")
}
}
}
class UserViewModel(private val repo: UserRepository) {
private val _state = MutableStateFlow<UiState<User>>(UiState.Loading)
val state: StateFlow<UiState<User>> = _state
fun loadUser(id: String) {
viewModelScope.launch {
try {
val user = repo.getUser(id)
_state.value = UiState.Success(user)
} catch (e: AppException) {
_state.value = UiState.Error(e.message ?: "Unknown")
}
}
}
}
Repository میں، تبدیلی کے ساتھ propagation: IOException (نیٹ ورک دستیاب نہیں) پر فنکشن ڈیٹا بیس سے کیشڈ ڈیٹا حاصل کرنے کی کوشش کرتا ہے۔ اگر کیش خالی ہے، تو AppException پھینکتا ہے — propagation نئی غلطی کی قسم کے ساتھ جاری رہتی ہے۔ ViewModel AppException کو پکڑتا ہے اور UiState.Error میں ترجمہ کرتا ہے — غلطی آگے نہیں جاتی، propagation UI پرت کی سطح پر ختم ہوتی ہے۔ Kotlin Coroutines خصوصیات شامل کرتے ہیں: launch میں استثنیٰ خود بخود CoroutineExceptionHandler کے ذریعے پھیلتی ہے، اور async میں — صرف await() کال کرنے پر۔ کوروٹینز میں propagation ڈیزائن کرتے وقت یہ اہم ہے — SupervisorJob چائلڈ کوروٹین میں غلطی پر پیرنٹ کوروٹین کی منسوخی کو روکتا ہے۔
استثنیات کا متبادل کنٹینر قسم کے ذریعے propagation ہے جو کامیابی یا غلطی کو ایک قدر کے طور پر منتقل کرتا ہے۔ اس طریقے میں، فنکشن قدر نہیں بلکہ ایک لفافہ لوٹاتا ہے: Swift میں Result<T, E>، Kotlin میں Result<T>، Dart میں Either<L, R> (fpdart یا dartz پیکیج سے)۔ غلطی اسٹیک نہیں کھولتی — یہ صرف کنٹینر کے اندر ہوتی ہے، اور اگلی سطح فیصلہ کرتی ہے کہ اس کے ساتھ کیا کرنا ہے۔ یہ propagation کو زیادہ واضح اور قابل کنٹرول بناتا ہے۔
data class HttpResult<out T>(
val data: T?,
val error: AppError?
) {
val isSuccess: Boolean get() = data != null
val isError: Boolean get() = error != null
}
sealed class AppError {
data class Network(val message: String) : AppError()
data class Auth(val message: String) : AppError()
}
fun fetchUser(id: String): HttpResult<User> {
return try {
val response = api.get("/users/$id")
HttpResult(data = parseUser(response), error = null)
} catch (e: IOException) {
HttpResult(data = null, error = AppError.Network("No internet"))
}
}
HttpResult<T> — data اور error فیلڈز والا سادہ کنٹینر۔ Sealed class AppError غلطی کی اقسام (Network، Auth) کی وضاحت کرتا ہے۔ fetchUser فنکشن HttpResult لوٹاتا ہے، propagation میں اسٹیک کھولنے کی ضرورت نہیں — کال کرنے والا صرف isSuccess/isError چیک کرتا ہے۔ یہ طریقہ خاص طور پر Clean Architecture میں مفید ہے، جہاں ہر پرت (data، domain، presentation) غلطی کو تبدیل کر سکتی ہے: IOError -> DomainError -> UiError۔ کنٹینر کے ذریعے propagation ان تبدیلیوں کو واضح اور قابل آزمائش بناتا ہے، استثنیات کے برعکس جہاں تبدیلی کی زنجیر فنکشن دستخطوں میں نظر نہیں آتی۔
غلطی ہینڈلنگ ڈیزائن میں اہم فیصلوں میں سے ایک propagation (اوپر منتقل کرنا) اور handling (یہاں ہینڈل کرنا) کے درمیان انتخاب ہے۔ فیصلہ کا اصول: غلطی کو اس سطح پر ہینڈل کریں جہاں بامعنی کارروائی کے لیے کافی سیاق و سباق ہو۔ اگر آپ کے پاس UI تک رسائی ہے — صارف کو پیغام دکھائیں۔ اگر آپ کے پاس کیش تک رسائی ہے — بحالی کی کوشش کریں۔ اگر کوئی نہیں ہے — propagate کریں۔
| منظر نامہ | عمل | وجہ |
|---|---|---|
| Repository میں نیٹ ورک کی غلطی | Propagate | Repository نہیں جانتا کہ صارف درخواست دہرانا چاہتا ہے یا نہیں |
| Repository میں تجزیہ کی غلطی | ہینڈل کریں (ڈیفالٹ لوٹائیں) | Repository فارمیٹ جانتا ہے، فال بیک قدر لوٹا سکتا ہے |
| ViewModel میں ٹائم آؤٹ | ہینڈل کریں (UiState.Error) | ViewModel UiState کا انتظام کرتا ہے، غلطی کا ترجمہ کرنا جانتا ہے |
| Interceptor میں اجازت کی غلطی | ہینڈل کریں (ٹوکن ریفریش) | Interceptor کو ٹوکنز تک رسائی ہے اور سیشن بحال کر سکتا ہے |
| UseCase میں نامعلوم غلطی | Propagate | UseCase کے پاس UI سیاق و سباق نہیں — صرف کاروباری منطق |
سنہری اصول: کم سے کم propagation، نچلی سطحوں پر زیادہ سے زیادہ handling۔ اگر Repository کیش سے بحال ہو سکتا ہے — اسے غلطی کو اوپر منتقل کیے بغیر ایسا کرنا چاہیے۔ اگر ViewModel Snackbar دکھا سکتا ہے — اسے دکھانے دیں، ViewController سے اضافی کوڈ کی ضرورت کے بغیر۔ propagation کی ہر سطح جوڑ کو بڑھاتی ہے اور جانچ کو پیچیدہ بناتی ہے۔ Google Android Architecture Guide (2026) کے مطابق، ViewModel سطح پر تمام ممکنہ حالات (Loading، Success، Error) کی نمائندگی کے لیے sealed class UiState استعمال کرکے اور استثنیات کو براہ راست UI پرت میں منتقل نہ کرکے پرت کی حدود میں propagation کو کم سے کم کرنے کی سفارش کی جاتی ہے۔
غلط propagation موبائل ایپلیکیشنز میں مشکل سے پکڑے جانے والے بگز کا ذریعہ ہے۔ آئیے پانچ اہم مسائل پر غور کریں جن کا ڈویلپرز کو سامنا ہے اور انہیں حل کرنے کے طریقے۔
سب سے عام مسئلہ: propagation کے دوران، ایک استثنیٰ پکڑی جاتی ہے، لاگ کی جاتی ہے اور اصل استثنیٰ کے بغیر نئی پھینکی جاتی ہے۔ ڈویلپر StackTrace کھو دیتا ہے اور سمجھ نہیں پاتا کہ غلطی بالکل کہاں ہوئی۔ Swift میں، غلطی کا سلسلہ استعمال کریں: throw MyError(context: originalError)۔ Kotlin میں: throw AppException(cause = originalException)۔ Dart میں: throw AppException(message, originalException)۔ cause/underlyingError منتقل کیے بغیر کبھی نیا استثنیٰ نہ بنائیں۔
catch (e: Exception) { /* کچھ نہیں */ } ایک اینٹی پیٹرن ہے جو ایپلیکیشن کو غلط حالت میں کام جاری رکھنے کا سبب بنتا ہے۔ اگر آپ کو یقین ہے کہ غلطی کو نظر انداز کیا جا سکتا ہے — جواز کے ساتھ تبصرہ شامل کریں۔ Swift میں اختیاری نظر انداز کرنے کے لیے try? (غلطی -> nil) استعمال کریں۔ Kotlin میں — Result<T>.onFailure { /* لاگ */ }۔ لاگنگ کے بغیر استثنیات کو نہ نگلیں۔
اگر غلطی بغیر ہینڈل کیے 5+ سطحوں سے گزرتی ہے، تو آرکیٹیکچر پر نظر ثانی کی ضرورت ہے۔ propagation کی ہر سطح بنیادی فنکشنز کے throws دستخط پر انحصار ہے۔ حل: پرت کی حدود پر ناکامی کے کنٹینر (sealed class Result { Success, Error }) استعمال کریں تاکہ propagation واضح اور محدود ہو۔ propagation کی زنجیر جتنی چھوٹی ہوگی، کوڈ کی جانچ اور ڈیبگ کرنا اتنا ہی آسان ہوگا۔
Kotlin Coroutines میں، launch میں استثنیٰ ڈیفالٹ طور پر پیرنٹ کوروٹین اور تمام siblings (اسی scope کے بچے) کو منسوخ کر دیتی ہے۔ اگر 10 متوازی کاموں میں سے ایک ناکام ہوتا ہے، تو باقی 9 منسوخ ہو جائیں گے، جو اکثر ناپسندیدہ ہے۔ غلطیوں کو الگ کرنے کے لیے SupervisorJob یا supervisorScope استعمال کریں: ایک بچے میں غلطی siblings کو منسوخ نہیں کرتی۔ ViewModelScope ڈیفالٹ طور پر SupervisorJob استعمال کرتا ہے، جو Android میں اس مسئلے سے بچاتا ہے۔
کال بیک پر مبنی API میں، غلطی اکثر کال بیک کے پیرامیٹر کے طور پر منتقل کی جاتی ہے۔ اگر کال بیک غلطی کو ہینڈل نہیں کرتا (یا غلط طریقے سے ہینڈل کرتا ہے)، تو propagation مضمر ہو جاتی ہے اور آسانی سے کھو جاتی ہے۔ حل: async/await (Swift) یا کوروٹینز (Kotlin) پر منتقل ہوں، جہاں propagation معیاری try-catch میکانزم کے ذریعے کام کرتی ہے۔ اگر کال بیک ناگزیر ہے — دونوں صورتوں کو ہینڈل کرنے پر مجبور کرنے کے لیے Either<Error, T> یا Result<T> استعمال کریں۔
اکثر پوچھے گئے سوالات
Throw ایک بار کی کارروائی ہے جو استثنیٰ پھینکتی ہے۔ Error Propagation throw سے catch تک کئی اسٹیک سطحوں کے ذریعے غلطی منتقل کرنے کا پورا عمل ہے۔ propagation میں throw، درمیانی فنکشنز کے ذریعے خودکار یا دستی منتقلی اور آخری ہینڈلنگ شامل ہے۔ یہ ایک وسیع تر تصور ہے جو غلطی کے لائف سائیکل کو بیان کرتا ہے۔
وہ mock آبجیکٹ استعمال کریں جو دیے گئے منظرناموں میں استثنیٰ پھینکتے ہیں۔ چیک کریں کہ فنکشن غلطی کو صحیح طریقے سے propagate یا ہینڈل کرتا ہے assertThrows (Kotlin/JUnit) یا XCTAssertThrowsError (Swift/XCTest) کے ذریعے۔ Result پر مبنی propagation کے لیے، isSuccess/isError اور دونوں صورتوں میں اقدار چیک کریں۔
Result propagation ایک آرکیٹیکچرل حد کے اندر متوقع غلطیوں (غلط ڈیٹا، کاروباری قواعد) کے لیے افضل ہے۔ استثنیات غیر متوقع غلطیوں (نیٹ ورک کا نقصان، I/O غلطیاں) کے لیے بہتر ہیں جنہیں اعلی سطح پر ہینڈل کیا جانا چاہیے۔ غلطی کے ساتھ نتیجہ عمل کے بہاؤ میں خلل نہیں ڈالتا، استثنیٰ ڈالتی ہے۔
Kotlin Coroutines میں، launch میں استثنیٰ siblings کی منسوخی کے ساتھ خود بخود CoroutineScope کے ذریعے propagate ہوتی ہے۔ علیحدگی کے لیے supervisorScope یا SupervisorJob استعمال کریں: ایک کوروٹین میں غلطی دوسروں کو منسوخ نہیں کرتی۔ async کے لیے، await() کال کرتے وقت try-catch کے ذریعے غلطی کو واضح طور پر ہینڈل کرنا ضروری ہے، ورنہ یہ نگل جائے گی۔
مثالی حتمی ہینڈلر UI پرت (ViewController، Fragment/Composable) ہے۔ صرف اس کے پاس یوزر انٹرفیس تک رسائی ہے اور یہ پیغام، Snackbar یا ڈائیلاگ دکھا سکتا ہے۔ درمیانی پرتیں (Repository، UseCase، ViewModel) غلطی کو propagate کرتی ہیں، اگر ضرورت ہو تو اسے مزید تجریدی ڈومین قسم میں تبدیل کرتی ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں