Non-Fatal Error في تطبيقات الجوال — الجوهر والأنواع ومعالجة الأخطاء

المؤلف: IT Sectr نُشر: 2026-05-27 وقت القراءة: 8 دق

Non-Fatal Error — هو خطأ لا يؤدي إلى إنهاء عمل التطبيق ويسمح بمواصلة تنفيذ البرنامج. على عكس الخطأ المميت، يمكن التقاط الأخطاء غير المميتة ومعالجتها وتسجيلها دون فقدان جلسة المستخدم. وفقًا لوثائق Firebase Crashlytics، 2024، حوالي 70% من جميع الأخطاء المسجلة في تطبيقات الإنتاج هي غير مميتة، لكن تجاهلها يؤدي إلى تراكم الديون الفني وتدهور تدريجي لتجربة المستخدم. المعالجة الصحيحة للأخطاء غير المميتة هي واحدة من المهارات الأساسية لمطور التطبيقات.

الخلاصة

  • Non-Fatal Error — خطأ لا ينهي التطبيق ويسمح باستئناف التنفيذ
  • المعالجة للأخطاء غير المميتة تشمل try-catch والتسجيل وعرض واجهة بديلة
  • تسجيل الأخطاء غير المميتة مهم جدًا لاكتشاف الأخطاء المخفية في الإنتاج
  • Fatal Error — العكس: خطأ يسبب تعطل التطبيق دون إمكانية التعافي
  • Crashlytics و Sentry يسمحان بتتبع الأخطاء غير المميتة في الوقت الفعلي

ما هو Non-Fatal Error

Non-Fatal Error — هو استثناء أو حالة خطأ لا تسبب إنهاء العملية. يستمر التطبيق في العمل، ولكنه قد يكون في حالة غير صحيحة: لم يتم تحميل البيانات، لم يتم إرسال الطلب، لم يتم عرض عنصر الواجهة. المستخدم إما لا يلاحظ الخطأ، أو يرى رسالة ويواصل استخدام التطبيق.

الخصائص الرئيسية

الخطأ غير المميت يترك دائمًا للبرنامج مسارًا للتعافي. يمكن لمعالج الأخطاء تقديم بيانات بديلة، إعادة المحاولة، أو عرض عنصر نائب في الواجهة. الهدف الرئيسي هو منع التعطل والحفاظ على تجربة مستخدم مقبولة. يجب على المطور أن يخطط صراحةً لسيناريو التعافي في كل كتلة catch.

الدور في استقرار التطبيقات

وفقًا لـ Instabug 2024، 65% من المستخدمين يحذفون التطبيق بعد تفاعلين فاشلين. الأخطاء غير المميتة التي تُترك دون معالجة تتراكم وتقلل الجودة العامة. التسجيل المنهجي وإصلاح الأخطاء غير المميتة هو طريق مباشر لتحسين الاحتفاظ بالمستخدمين ورفع التقييمات في متاجر التطبيقات.

أنواع الأخطاء غير المميتة

أخطاء الشبكة هي النوع الأكثر شيوعًا من الأخطاء غير المميتة في تطبيقات الجوال. انتهاء مهلة الاتصال، فقدان الشبكة، رمز حالة خادم غير صحيح — كل هذه الحالات يتم التقاطها ومعالجتها دون تعطل. تظهر للمستخدم رسالة عدم توفر الخدمة مع خيار إعادة المحاولة. نمط إعادة المحاولة مع التأخير الأسي هو النمط النموذجي لأخطاء الشبكة.

أخطاء التحقق من البيانات

تنسيق استجابة خادم غير صحيح، حقل إجباري مفقود، نوع بيانات غير صالح — أخطاء التحليل غير مميتة إذا كان التطبيق يعالج البيانات غير الصحيحة بشكل صحيح. النهج النموذجي هو استخدام قيم افتراضية احتياطية وتسجيل خطأ التحليل مع سياق الطلب لتحليل لاحق على الخادم.

أخطاء عرض واجهة المستخدم

مشاكل تحميل الصور، خطوط غير صحيحة، أخطاء في التخطيط — كلها غير مميتة ولكنها تقلل من تجربة المستخدم. صور العناصر النائبة والقيم الاحتياطية تساعد في تجنب الشاشات الفارغة وتجعل الأخطاء أقل وضوحًا. في React Native، يتم استخدام Error Boundary لأخطاء واجهة المستخدم مع عرض مكون بديل.

أخطاء منطق الأعمال والحالة

أخطاء في الحسابات، عدم تطابق الحالة، انتقالات غير صحيحة بين الشاشات — الأخطاء المنطقية غالبًا لا تسبب تعطلاً ولكنها تؤدي إلى سلوك غير صحيح للتطبيق. يصعب اكتشافها دون تسجيل ومراقبة منهجيين لأنها لا تنشئ تقرير تعطل وتبقى غير ملحوظة حتى شكوى المستخدم.

مقارنة: Non-Fatal Error vs Fatal Error

Non-Fatal Error يختلف عن الخطأ المميت في أنه يترك للبرنامج فرصة لمواصلة العمل. الخطأ المميت هو حالة لا يمكن للتطبيق التعافي منها: إلغاء مرجع مؤشر فارغ، تجاوز سعة المكدس، نفاد الذاكرة. يمكن التقاط الخطأ غير المميت ومعالجته ومواصلة التنفيذ، بينما يتطلب الخطأ المميت إعادة تشغيل التطبيق.

الخاصيةNon-Fatal ErrorFatal Error
إنهاء التطبيقلانعم
إمكانية التعافينعم، عبر catchلا
التسجيلمن الكود عبر recordExceptionفقط بواسطة مبلغ التعطل
تأثير على تجربة المستخدمإزعاج مؤقتفشل كامل للجلسة
مثالمهلة شبكة، خطأ تحليلNullPointerException, OOM

الحدود بين non-fatal و fatal قد تعتمد على التنفيذ. مهلة الشبكة في تطبيق تُعالج كغير مميتة (إعادة محاولة بعد 1–2 ثانية)، بينما في آخر قد تكون مميتة (تعطل في حالة عدم وجود معالج). معالجة الأخطاء عالية الجودة تحول المواقف التي قد تكون مميتة إلى غير مميتة، مما يزيد من استقرار التطبيق. تصميم نظام معالجة الأخطاء هو أحد المهام المعمارية الرئيسية عند تطوير تطبيق جوال بمتطلبات موثوقية عالية. نظام مراقبة مدمج يسمح للفريق باكتشاف وإصلاح الأخطاء غير المميتة بسرعة قبل أن تؤثر على عدد كبير من المستخدمين.

تسجيل الأخطاء غير المميتة

Firebase Crashlytics هو الأداة الرئيسية لتسجيل الأخطاء غير المميتة في تطبيقات الجوال. تتيح طريقة recordException التقاط استثناء غير مميت مع تتبع كامل للمكدس وسياق التنفيذ دون مقاطعة التطبيق. على عكس تقارير التعطل، يمكن استدعاء recordException في أي مكان في الكود لتسجيل الاستثناءات التي تم التقاطها.

kotlin
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 مع تشخيص أكثر تفصيلاً للأخطاء غير المميتة. يوفر Sentry SDK طريقة captureException التي ترسل تفاصيل الاستثناء إلى الخادم. الميزة الرئيسية لـ Sentry هي تجميع الأخطاء غير المميتة المتشابهة في مشكلة واحدة، وتحليل تكرار الحدوث، وتوفير سياق التنفيذ في شكل breadcrumbs — تسلسل إجراءات المستخدم قبل الخطأ.

معايير تسجيل الأخطاء غير المميتة

ليست كل الأخطاء غير المميتة تحتاج إلى تسجيل. الحالات المتوقعة — فشل الشبكة عند عدم وجود اتصال — يمكن تسجيلها بشكل انتقائي. الأخطاء غير المتوقعة — NullPointerException في كود معالج، تنسيق بيانات غير صالح، أخطاء منطقية — يجب تسجيلها دائمًا. كل فريق يحدد عتبة الأهمية الخاصة به: في المتوسط، 10 إلى 20 خطأ غير مميت فريد لكل 1000 مستخدم يوميًا يعتبر طبيعيًا. من المهم إعداد تنبيهات للزيادة الحادة في الأخطاء غير المميتة — قد يشير ذلك إلى مشاكل في إصدار API جديد أو تراجع بعد الإصدار.

معالجة الأخطاء غير المميتة في الكود

الآلية الأساسية للمعالجة هي try-catch، التي تلتقط الاستثناء وتنفذ كود التعافي. لعمليات الشبكة، النمط النموذجي هو إعادة المحاولة مع التأخير الأسي. لأخطاء التحليل، النهج هو استخدام قيم افتراضية احتياطية وتسجيل السياق لتحليل لاحق في الخادم.

swift
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 — نهج بديل بدون استثناءات. ترجع الدالة فئة Result مختومة مع خيارات Success و Failure. الكود المستديع يعالج كلا الخيارين بشكل صريح، مما يلغي الأخطاء غير المعالجة. أنواع Result شائعة في Kotlin (Result في المكتبة القياسية) و Swift (Result) للمعالجة الصريحة للحالات غير المميتة على مستوى الأنواع.

استراتيجيات الاحتياط للأخطاء غير المميتة

لكل نوع من الأخطاء غير المميتة، يجب التخطيط لاستراتيجية تعافي: تحميل البيانات المخزنة مؤقتًا عند خطأ الشبكة، استخدام القيم الافتراضية عند خطأ التحليل، إعادة تهيئة المكون عند خطأ واجهة المستخدم. الممارسة الجيدة هي عرض رسالة خطأ للمستخدم عبر toast أو snackbar دون حظر التفاعل مع التطبيق بالكامل. من المهم التمييز بين الأخطاء القابلة للاسترداد وغير القابلة للاسترداد — لهذه الأخيرة، ستكون استراتيجية التعافي مختلفة، مثل اقتراح إعادة تشغيل الشاشة أو مسح البيانات. التخزين المؤقت للحالة الناجحة السابقة هو غالبًا الطريقة الأبسط والأكثر فعالية لمعالجة الأخطاء غير المميتة على المنصات المحمولة.

الأسئلة الشائعة

كيف يختلف الخطأ غير المميت عن التحذير؟

التحذير هو تنبيه من المترجم أو المحلل الثابت حول مشكلة محتملة في الكود. الخطأ غير المميت هو استثناء وقت تشغيل حدث بالفعل لكنه لم يؤد إلى تعطل. يمكن إصلاح التحذير قبل التجميع؛ بينما يجب معالجة الخطأ غير المميت أثناء التنفيذ عبر كتلة catch.

هل يجب تسجيل جميع الأخطاء غير المميتة؟

لا، التسجيل المفرط يزعج المراقبة. يجب تسجيل الأخطاء غير المتوقعة في الإنتاج وتجاهل الحالات المتوقعة: فشل الشبكة عند عدم الاتصال يمكن تسجيله بشكل انتقائي، لكن NullPointerException في كود معالج يجب تسجيله دائمًا. كل فريق يحدد عتبة الأهمية حسب سياق التطبيق.

كيف نعالج خطأ غير مميت في SwiftUI؟

في SwiftUI، يُستخدم ObservableObject مع حقل @Published errorState لتتبع حالة الخطأ. تشترك view في التغييرات وتعرض محتوى بديل. قبل iOS 17، كان يُستخدم Combine مع معالجات؛ بدءًا من iOS 17، تُستخدم SwiftData ووحدات @Observable للتحديثات التفاعلية للواجهة.

هل يمكن أن يصبح الخطأ غير المميت مميتًا؟

نعم، إذا تسبب الخطأ في تفاعل تسلسلي. مثال: فشل غير مميت في تحميل صورة يمكن أن يؤدي إلى حالة واجهة غير صحيحة، والتي تسبب بعد ذلك تعطلًا عند محاولة العرض. المعالجة عالية الجودة للأخطاء غير المميتة في كل مستوى تمنع تصعيدها إلى المستوى المميت.

كيف يختلف non-fatal بين iOS و Android؟

في iOS، تُعالج الأخطاء غير المميتة عبر do-catch مع throw؛ في Android، عبر try-catch مع الاستثناءات. يستخدم iOS NSError مع نطاقات ورموز خطأ؛ يستخدم Android استثناءات Java/Kotlin. يعمل Crashlytics بشكل متطابق على كلا المنصتين عبر recordException، مما يوفر واجهة مراقبة موحدة.

الملخص

  • Non-Fatal Error — خطأ وقت تشغيل لا ينهي التطبيق ويسمح باستئناف التنفيذ
  • أخطاء الشبكة، أخطاء التحليل، وأخطاء عرض واجهة المستخدم — الفئات الثلاث الرئيسية للأخطاء غير المميتة
  • Fatal Error — عكس non-fatal، يسبب تعطلًا كاملاً للتطبيق دون تعافي
  • Crashlytics و Sentry — الأدوات الرئيسية لتسجيل الأخطاء غير المميتة في الإنتاج
  • أنواع Result — بديل للاستثناءات للمعالجة الصريحة لحالات الخطأ على مستوى الأنواع
  • قيم العناصر النائبة والاستراتيجيات الاحتياطية تمنع التدهور الملحوظ لتجربة المستخدم
  • الإصلاح المنهجي للأخطاء غير المميتة يحسن الاحتفاظ بالمستخدمين وجودة التطبيق وفقًا لـ Instabug

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا