معالجة الأخطاء في Swift: try/catch والتقنيات المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

معالجة الأخطاء في Swift: try/catch وأكثر (مستوى متقدم)

\n\n

معالجة الأخطاء هي أحد الموضوعات الأساسية في التطوير باستخدام Swift. إذا كنت بالفعل على دراية بـ do-catch و try? الأساسيين، فقد حان الوقت للانتقال إلى المستوى التالي. في هذه المقالة، سنستعرض التقنيات المتقدمة: العمل مع بروتوكول Error، ونوع Result، والكلمة المفتاحية rethrows، بالإضافة إلى كيفية تصميم تسلسل هرمي للأخطاء بشكل صحيح في مشاريع iOS/macOS الحقيقية.

\n\n

غوص عميق في بروتوكول Error والأخطاء المخصصة

\n\n

في Swift، يجب أن يتوافق أي خطأ مع بروتوكول Error. ومع ذلك، لجعل الكود أكثر قابلية للقراءة والصيانة، يُنصح بإنشاء تعدادات (enum) خاصة بك تحتوي على حالات متداخلة وقيم مرتبطة.

\n\n
enum NetworkError: Error {\n    case invalidURL\n    case noData\n    case decodingFailed(description: String)\n    case serverError(statusCode: Int)\n    case timeout(seconds: Double)\n}\n\n// مثال على الاستخدام\nfunc fetchUser(id: Int) throws -> User {\n    guard id > 0 else {\n        throw NetworkError.invalidURL\n    }\n    // ... منطق الطلب\n    if someCondition {\n        throw NetworkError.serverError(statusCode: 500)\n    }\n    return User()\n}
\n\n

يسمح هذا الأسلوب بنقل سياق إضافي: رمز الخطأ، الوصف، أو وقت الانتظار. هذا مفيد بشكل خاص في تسجيل الأخطاء وتصحيحها.

\n\n

Result: بديل لـ do-catch للكود غير المتزامن

\n\n

نوع Result<Success, Failure> هو أداة قوية جاءت من البرمجة الوظيفية. إنه مثالي لواجهات برمجة التطبيقات القائمة على الاستدعاءات (callback-based API)، والطلبات الشبكية، والعمليات غير المتزامنة.

\n\n
enum DataError: Error {\n    case corrupted\n    case notFound\n}\n\nfunc loadImage(from url: URL, completion: @escaping (Result<UIImage, DataError>) -> Void) {\n    DispatchQueue.global().async {\n        // محاكاة التحميل\n        if arc4random_uniform(2) == 0 {\n            completion(.success(UIImage()))\n        } else {\n            completion(.failure(.notFound))\n        }\n    }\n}\n\n// الاستخدام\nloadImage(from: someURL) { result in\n    switch result {\n    case .success(let image):\n        print("تم تحميل الصورة: \\(image)")\n    case .failure(let error):\n        print("خطأ: \\(error.localizedDescription)")\n    }\n}
\n\n

يجعل Result الكود أكثر قابلية للتنبؤ ويخلصك من الحاجة إلى معالجة القيم الاختيارية مع nil. بالإضافة إلى ذلك، يمكنك استخدام .map و .flatMap لسلاسل التحويلات.

\n\n

Rethrows: عندما "تمرر" الدالة الأخطاء

\n\n

الكلمة المفتاحية rethrows هي واحدة من أكثر إمكانيات Swift التي لا تحظى بالتقدير الكافي. تسمح لك بكتابة دالة لا ترمي الأخطاء بنفسها، ولكنها "تمررها" إذا كان الإغلاق (closure) المُمرر هو throws.

\n\n
func performOperation<T>(on array: [T], operation: (T) throws -> Bool) rethrows -> [T] {\n    var result: [T] = []\n    for element in array {\n        if try operation(element) {\n            result.append(element)\n        }\n    }\n    return result\n}\n\n// بدون أخطاء (لا حاجة لـ try)\nlet numbers = [1, 2, 3, 4, 5]\nlet evenNumbers = performOperation(on: numbers) { $0.isMultiple(of: 2) }\nprint(evenNumbers) // [2, 4]\n\n// مع خطأ (بحاجة لـ try)\nenum ValidationError: Error { case negative }\nlet filtered = try performOperation(on: numbers) { value in\n    guard value > 0 else { throw ValidationError.negative }\n    return value % 2 == 0\n}
\n\n

يجعل rethrows واجهة برمجة التطبيقات مرنة: يمكن للمستخدم تمرير إغلاق عادي (بدون try) أو إغلاق مع throws (عندها سيكون try مطلوبًا). يُستخدم هذا غالبًا في المكتبة القياسية لـ Swift - على سبيل المثال، في map و filter و for

المدونات

توصيات الكتب