Non-Fatal Error — грешка која не доводи до завршетка рада апликације и омогућава наставак извршења програма. За разлику од fatal error, нефаталне грешке могу бити пресретнуте, обрађене и логоване без губитка корисничке сесије. Према подацима Firebase Crashlytics Documentation, 2024, око 70% свих забележених грешака у production апликацијама су нефаталне, али њихово игнорисање води ка акумулацији техничког дуга и постепеном погоршању корисничког искуства. Коректна обрада non-fatal грешака је једна од кључних вештина мобилног програмера.
Главне тачке
Non-Fatal Error — изузетак или грешно стање које не изазива завршетак процеса. Апликација наставља да ради, али може бити у неисправном стању: подаци се нису учитали, захтев се није послао, елемент интерфејса се није приказао. Корисник или не примећује грешку или види поруку и наставља коришћење апликације.
Нефатална грешка увек оставља програму пут за обнављање. Руковалац грешкама може понудити алтернативне податке, поновити операцију или приказати чувар места интерфејса. Главни задатак је спречити crash и одржати корисничко искуство на прихватљивом нивоу. Програмер мора експлицитно предвидети сценариј обнављања у сваком catch блоку.
Према подацима Instabug 2024, 65% корисника брише апликацију након две неуспеле интеракције. Non-fatal грешке остављене без пажње се акумулирају и смањују укупан квалитет рада. Систематско логовање и исправљање нефаталних грешака је директан пут ка повећању retention и побољшању корисничких оцена у продавницама апликација.
Мрежне грешке — најчешћи тип non-fatal грешака у мобилним апликацијама. Прекорачење времена за повезивање, губитак мреже, неисправан статусни код сервера — све ове ситуације се пресрећу и обрађују без crash-а. Кориснику се приказује порука о недоступности услуге са предлогом поновног покушаја. За мрежне грешке типичан је образац retry са експоненцијалним кашњењем.
Неисправан формат одговора сервера, недостатак обавезног поља, неисправан тип података — грешке парсирања су нефаталне ако апликација коректно обрађује неисправне податке. Типичан приступ је коришћење подразумеваних резервних вредности и логовање грешке парсирања са контекстом захтева за каснију анализу на серверу.
Проблеми са учитавањем слика, неисправни фонтови, грешке у layout-у — све то није фатално, али погоршава утисак корисника. Placeholder слике и fallback вредности омогућавају избегавање празних екрана и чине грешке мање приметним. У React Native за UI грешке се користи Error Boundary са приказом резервне компоненте.
Грешке у прорачунима, неусклађеност стања, неисправни прелази између екрана — логичке грешке често не доводе до crash-а, али доводе до неисправног понашања апликације. Теже их је открити без систематског логовања и мониторинга јер не креирају crash извештај и остају непримећене до жалбе корисника.
Non-Fatal Error се разликује од fatal по томе што оставља програму могућност да настави рад. Fatal error — стање из којег апликација не може да се опорави: дереференцирање null показивача, прекорачење стека, недостатак меморије. Non-fatal грешка се може пресрести, обрадити и наставити извршење, док fatal error захтева поновно покретање апликације.
| Карактеристика | Non-Fatal Error | Fatal Error |
|---|---|---|
| Завршетак апликације | Не | Да |
| Могућност обнављања | Да, кроз catch блок | Не |
| Логовање | Из кода кроз recordException | Само crash извештавачем |
| UX утицај | Привремена неугодност | Потпуни губитак сесије |
| Пример | Network timeout, parse error | NullPointerException, OOM |
Граница између non-fatal и fatal може зависити од имплементације. Мрежни timeout у једној апликацији се обрађује као non-fatal (понављање захтева након 1–2 секунде), у другој може бити фаталан (crash без руковаоца). Квалитетна обрада грешака претвара потенцијално фаталне ситуације у нефаталне, повећавајући стабилност апликације. Пројектовање система за обраду грешака је један од кључних архитектонских задатака при развоју мобилне апликације са високим захтевима за поузданост. Уграђени систем мониторинга омогућава тиму да брзо открива и отклања нефаталне грешке пре него што утичу на значајан број корисника.
Firebase Crashlytics — основни алат за логовање нефаталних грешака у мобилним апликацијама. Метода recordException омогућава бележење non-fatal изузетка са комплетним стек трејсом и контекстом извршења, без прекидања рада апликације. За разлику од crash извештаја, recordException се може позвати на било ком месту у коду за логовање пресретнутих изузетака.
fun fetchUserData(userId: String) {
try {
val response = apiService.getUser(userId)
updateUI(response)
} catch (e: IOException) {
Crashlytics.log("Network error for user $userId")
Crashlytics.recordException(e)
showRetryDialog()
} catch (e: JsonParseException) {
// Non-fatal: користимо резервне податке
Crashlytics.recordException(e)
showFallbackContent()
}
}
// Логовање са корисничким кључевима
Crashlytics.setCustomKey("screen", "Profile")
Crashlytics.setCustomKey("api_version", "v3")
Sentry — алтернатива Crashlytics-у са детаљнијом дијагностиком non-fatal грешака. Sentry SDK пружа методу captureException која шаље детаље изузетка на сервер. Кључна предност Sentry-ја је груписање сличних non-fatal грешака у један issue, анализа учесталости понављања и контекст извршења у облику breadcrumbs — секвенце радњи корисника пре грешке.
Није све non-fatal грешке потребно логовати. Очекивана стања — недостатак мреже при одсуству конекције — могу се логовати селективно. Неочекиване грешке — NullPointerException у обрађеном коду, неисправан формат података, logic error — треба увек логовати. Сваки тим одређује праг значајности: у просеку од 10 до 20 јединствених non-fatal грешака на 1000 корисника дневно сматра се нормом. Важно је подесити аларме на нагли пораст броја non-fatal грешака — то може указивати на проблеме са новом верзијом API-ја или регресију након издања.
Основни механизам обраде — try-catch, који пресреће изузетак и извршава код за обнављање. За мрежне операције типичан образац је понављање захтева са експоненцијалним кашњењем (retry with backoff). За грешке парсирања — коришћење подразумеваних резервних вредности и логовање контекста за каснију анализу на серверској страни.
func loadImage(from url: URL) -> UIImage? {
do {
let data = try Data(contentsOf: url)
return UIImage(data: data)
} catch {
Logger.shared.logError(error: "Image load failed: \(url)")
return UIImage(named: "placeholder")
}
}
func performRequest() async throws -> Data {
var lastError: Error? = nil
for attempt in 0..<3 {
do {
return try await URLSession.shared.data(from: url)
} catch {
lastError = error
try await Task.sleep(UInt64(pow(2, attempt)) * 1_000_000_000)
}
}
throw lastError ?? URLError(.unknown)
}
Result типови — алтернативни приступ без изузетака. Функција враћа sealed class Result са варијантама Success и Failure. Позивајући код обрађује обе варијанте експлицитно, што елиминише необрађене грешке. Result типови су популарни у Kotlin (Result
За сваки тип non-fatal грешке треба предвидети стратегију обнављања: учитавање кешираних података при мрежној грешци, коришћење подразумеваних вредности при грешци парсирања, поновна иницијализација компоненте при UI грешци. Добра пракса је приказати кориснику toast или snackbar са поруком о грешци, али не блокирати у потпуности интеракцију са апликацијом. Важно је разликовати обновљиве (recoverable) и необновљиве грешке — за друге стратегија обнављања ће бити другачија, на пример, предлог за поновно покретање екрана или чишћење података. Кеширање претходног успешног стања често је најједноставнији и најефикаснији начин обраде non-fatal грешака на мобилним платформама.
Често постављана питања
Warning — упозорење компајлера или статичког анализатора о потенцијалном проблему у коду. Non-fatal error — runtime изузетак који се већ десио, али није довео до crash-а. Warning се може отклонити пре компајлације, non-fatal error — обрадити током извршења кроз catch блок.
Не, прекомерно логовање затрпава мониторинг. Треба логовати неочекиване грешке у production и игнорисати очекивана стања: недостатак мреже при одсуству конекције логује се селективно, а NullPointerException у обрађеном коду — увек. Сваки тим одређује праг значајности на основу контекста апликације.
У SwiftUI се користи ObservableObject са @Published пољем errorState за праћење грешног стања. View се претплаћује на промене и приказује алтернативни садржај. До iOS 17 примењивао се Combine са руковаоцима, од iOS 17 — SwiftData и @Observable макрои за реактивно ажурирање UI.
Да, ако грешка изазива ланчану реакцију. Пример: нефатални квар при учитавању слике може довести до неисправног стања UI, које затим изазива crash при покушају приказа. Квалитетна обрада non-fatal грешака на сваком нивоу спречава њихову ескалацију на фатални ниво.
У iOS-у non-fatal грешке се обрађују кроз do-catch са throw, у Android-у — кроз try-catch са изузецима. iOS користи NSError са доменима и кодовима грешака, Android — Java/Kotlin изузетке. Crashlytics ради исто на обе платформе кроз recordException, пружајући јединствени интерфејс за мониторинг.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође