إلغاء التسلسل: ما هو، عملية استعادة البيانات

المؤلف: IT Sectr نُشر: 2026-03-08 وقت القراءة: 9 دق

إلغاء التسلسل هو عملية استعادة كائن من تدفق بيانات JSON أو XML أو Protobuf، وهي ضرورية لأي تطبيق محمول يعمل مع API عن بُعد. وفقًا لـ Apple Developer (2026)، لا يزال التعامل غير الصحيح مع البيانات الواردة أحد الأسباب الشائعة للانهيارات على الأجهزة. JSONDecoder على iOS و Gson على Android هما أداتان قياسيتان، لكن لكل منهما ميزاته وقيوده الخاصة.

الخلاصة

  • إلغاء التسلسل هو استعادة كائن مُنمّط من JSON أو XML أو Protobuf لاستخدامه في الكود.
  • Codable هو بروتوكول Apple لإلغاء التسلسل التلقائي في Swift مع دعم توليد الكود.
  • Moshi هي مكتبة Android من Square مع خيارات codegen و reflection لسيناريوهات مختلفة.
  • عدم تطابق النوع هو الخطأ الأكثر شيوعًا عندما لا تتطابق أنواع حقول JSON مع خصائص النموذج.
  • kotlinx.serialization هو الحل الرسمي من JetBrains مع توليد كود آمن عن طريق المترجم.

ما هو إلغاء التسلسل؟

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

الفرق عن التسلسل

التسلسل وإلغاء التسلسل هما عمليتان متعاكستان، ونادرًا ما تكونان متماثلتين عمليًا. التسلسل يحول كائنًا إلى سلسلة لإرسالها إلى الخادم، بينما إلغاء التسلسل يستعيد الكائن من السلسلة المستلمة. قد يرسل الخادم حقلاً غير موجود في نموذج العميل، أو يستخدم تنسيق تاريخ مختلف، أو يعيد null بدلاً من رقم. وفقًا لـ Square Engineering (2025)، يتسبب عدم تماثل التنسيقات في 23% من أخطاء طبقة الشبكة في تطبيقات Android. لتقليل المخاطر، يتم استخدام إدارة إصدارات المخطط ومواصفات العقود الصارمة عبر OpenAPI.

تنسيقات البيانات لإلغاء التسلسل

JSON يظل التنسيق الأكثر شيوعًا لواجهات API المحمولة بفضل سهولة قراءته البشرية ودعمه المدمج. Protobuf من Google يُستخدم في الأنظمة عالية الحمل — فهو أصغر بنسبة 3-6 مرات من JSON ويتم تحليله بشكل أسرع، لكنه يتطلب توليد كود من ملفات .proto وغير قابل للقراءة بدون أدوات. XML أقل شيوعًا في التطبيقات المحمولة الحديثة، لكنه يُستخدم في خدمات SOAP للأنظمة المؤسسية وملفات تهيئة Android. MessagePack هو تنسيق ثنائي مشابه لـ JSON في الهيكل لكنه أكثر compact، شائع في أنظمة الوقت الفعلي.

كيف يعمل إلغاء التسلسل

تمر عملية إلغاء التسلسل بثلاث مراحل. أولاً، الترميز يقسم النص الخام إلى رموز: مفاتيح وسلاسل وأرقام وفواصل. ثم التحليل النحوي يتحقق من صحة الهيكل — هل الأقواس مغلقة، هل نوع علامات الاقتباس صحيح، هل التنسيق يتوافق مع RFC 8259. المرحلة النهائية هي التعيين إلى نموذج الكائنات للتطبيق، حيث يتم تعيين خاصية فئة لكل مفتاح JSON مع مراعاة استراتيجية التسمية.

Reflection مقابل Code generation

ظهر نهجان للتعيين في تطوير التطبيقات المحمولة. Reflection (Gson, JSONSerialization) يحلل هيكل الفئة في وقت التشغيل عبر Java Reflection API أو Objective-C runtime — وهو مرن ولا يتطلب تهيئة إضافية، لكنه أبطأ ويستهلك ذاكرة أكثر. Code generation (Moshi codegen, kotlinx.serialization, Codable) يولد الكود في وقت الترجمة: أسرع وأكثر أمانًا من حيث الأنواع ولا يكشف الهيكل الداخلي عبر reflection. توصي JetBrains و Square بتوليد الكود لإصدارات الإنتاج — يصل تحسين الأداء إلى 2-4 مرات في معايير Google.

swift
struct User: Codable {
    let id: Int
    let name: String
    let email: String
    let createdAt: Date
}

let json = """
{
    "id": 42,
    "name": "Alice",
    "email": "alice@example.com",
    "created_at": "2026-06-01T12:00:00Z"
}
"""
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: data)

مثال على إلغاء تسلسل JSON إلى نموذج User في Swift. استراتيجية convertFromSnakeCase تحول تلقائيًا مفاتيح API بصيغة snake_case إلى خصائص النموذج بصيغة camelCase — وهي ممارسة قياسية في مشاريع iOS. المعامل data هو البايتات الخام لاستجابة الخادم المستلمة عبر URLSession. معالجة الأخطاء عبر try تسمح بالتقاط JSON غير الصحيح دون تعطل التطبيق.

دور استراتيجيات فك الترميز

يدعم JSONDecoder أربع استراتيجيات للمفاتيح: useDefaultKeys (مطابقة تامة)، convertFromSnakeCase (snake_case → camelCase)، custom (closure) و convertFromKebabCase (kebab-case → camelCase). للتواريخ، تتوفر .iso8601 و .secondsSince1970 و .millisecondsSince1970 و dateFormatter مخصص. اختيار الاستراتيجية الصحيحة هو الخطوة الأولى نحو إلغاء تسلسل قوي، يمنع معظم أخطاء عدم تطابق التنسيقات.

إلغاء التسلسل على iOS

JSONDecoder هو الآلية القياسية لإلغاء التسلسل في iOS SDK، ويعمل مع بروتوكول Codable. يقوم JSONDecoder تلقائيًا بتحليل JSON إلى مثيلات struct أو class، ويدعم الكائنات المتداخلة والمصفوفات والأنواع البدائية. للمنطق المخصص، يتم استخدام طريقة init(from: Decoder) — وهي تسمح بمعالجة التنسيقات غير القياسية والحقول المفقودة في إصدار قديم من API أو دمج عدة مفاتيح JSON في خاصية واحدة.

swift
struct Order: Decodable {
    let orderId: String
    let amount: Double
    let status: OrderStatus

    enum OrderStatus: String, Decodable {
        case pending, confirmed, shipped, cancelled
    }
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let order = try decoder.decode(Order.self, from: jsonData)

DateDecodingStrategy تحدد كيفية تفسير JSONDecoder لسلاسل التاريخ. .iso8601 هو الأكثر استخدامًا — التنسيق القياسي لواجهات REST API. التعداد المتداخل OrderStatus يتم فك ترميزه تلقائيًا من قيم السلاسل في JSON. هذا يتجنب الأرقام السحرية ويجعل الكود موثقًا ذاتيًا — حالة الطلب دائمًا لها مجموعة محددة بدقة من القيم.

Property Wrappers في Codable

منذ Swift 4.2، يدعم Codable property wrappers لإلغاء التسلسل المخصص للخصائص الفردية. @DefaultValue هو wrapper شائع يعين قيمة افتراضية إذا كان الحقل مفقودًا في JSON. @LosslessString يحول سلسلة إلى رقم والعكس. هذا مفيد بشكل خاص عندما يرسل الخادم id كسلسلة "123" لكن النموذج يتوقع Int. تقلل property wrappers من الكود المتكرر في init(from:) وتجعل النماذج أنظف.

إلغاء التسلسل على Android

على Android، يعتمد اختيار مكتبة إلغاء التسلسل على اللغة ومتطلبات المشروع. Gson من Google هو الخيار الأكثر شيوعًا، ويعمل عبر reflection لكن لديه مشاكل في الأداء مع التسلسلات الهرمية المعقدة. Moshi من Square يدعم كلاً من reflection و code generation، ويستهلك ذاكرة أقل ويعالج الاستجابات الكبيرة بشكل أسرع. kotlinx.serialization من JetBrains هو حل Kotlin أصلي مع تكامل في المترجم ولا يستخدم reflection على الإطلاق.

kotlin
@Serializable
data class User(
    @SerialName("user_id")
    val userId: Int,
    val name: String,
    val email: String,
    @SerialName("created_at")
    val createdAt: String
)

val json = Json { ignoreUnknownKeys = true }
val user = json.decodeFromString<User>(response)

@Serializable هو تعليق توضيحي لمترجم Kotlin ينشط توليد الكود للفئة. المعامل ignoreUnknownKeys يمنع الانهيار إذا أرسل الخادم حقلاً مفقودًا في النموذج. لتعيين مفاتيح snake_case، يُستخدم @SerialName — وهو ما يعادل convertFromSnakeCase من iOS. وفقًا لـ JetBrains (2026)، تدعم المكتبة تعدد المنصات: نفس الفئة Serializable تعمل على Android و iOS (KMP) و Kotlin من جانب الخادم.

مقارنة Gson و Moshi و kotlinx.serialization

الاختيار بين المكتبات يعود إلى مفاضلة بين السرعة والمرونة. Gson جيد للنماذج الأولية ومشاريع Java — لا يتطلب تعليقات توضيحية ويعمل فورًا. Moshi يحتل موقعًا وسطًا: codegen عبر @JsonClass(generateAdapter = true) يعطي سرعة قريبة من kotlinx.serialization، بينما وضع reflection يوفر مرونة Gson. kotlinx.serialization هو الخيار الأسرع لمشاريع Kotlin النقية لكنه يتطلب Kotlin 1.4+ وإضافة Kotlin Serialization في Gradle.

المكتبةالآليةالسرعةKMP
GsonReflectionمنخفضةلا
MoshiReflection / Codegenمتوسطة / عاليةلا
kotlinx.serializationCodegen المترجمعاليةنعم

الأخطاء النموذجية ومنعها

عدم تطابق النوع هو حالة يحتوي فيها JSON على قيمة من نوع بينما يتوقع النموذج نوعًا آخر. أرسل الخادم السلسلة "42" بدلاً من رقم، أو الرقم 1 بدلاً من true المنطقي. على iOS، سيرمي JSONDecoder خطأ DecodingError.typeMismatch افتراضيًا؛ على Android، سيحاول Gson التحويل، بينما يتطلب Moshi و kotlinx.serialization محولات صريحة. الحل هو استخدام استراتيجيات lenient أو أدوات إلغاء تسلسل مخصصة لحقول محددة.

الحقول المفقودة والقابلة للعدم

عندما لا يتضمن الخادم حقلاً اختياريًا، ينهار الكود مع خطأ. الحقول Optional في Swift والأنواع القابلة للعدم في Kotlin تحل المشكلة: إذا كان الحقل null أو مفقودًا في JSON، تحصل الخاصية على nil/null ويستمر التطبيق في العمل. للحقول الإلزامية، من الجيد التحقق من وجودها على مستوى عميل API قبل إلغاء التسلسل. تتطلب Moshi و kotlinx.serialization جميع الحقول افتراضيًا — العلامات القابلة للعدم والقيم الافتراضية تزيل هذا القيد.

عدم توافق إصدارات API

تغيير هيكل JSON على الخادم هو مصدر شائع لانهيارات الإنتاج. الممارسة القياسية هي إدارة إصدارات المخطط عبر حقل version في الكائن الجذر ودعم 2-3 إصدارات سابقة على العميل. kotlinx.serialization تسمح بتعريف نماذج متعددة لإصدارات مختلفة واختيار النموذج المناسب بناءً على حقل version بعد التحليل الأولي إلى JsonElement. الحماية الإضافية تشمل ignoreUnknownKeys للحقول الجديدة والقيم الافتراضية للحقول التي قد تُحذف.

الخطأالعرضالمكتبة مع الحماية
عدم تطابق النوعDecodingError / استثناءkotlinx — coerceInputValues = true
حقل مفقودانهيار عند الوصولMoshi — @Transient + default
تنسيق تاريخ غير صحيحخطأ في فك الترميزJSONDecoder — dateDecodingStrategy
حقول إضافيةتُتجاهل أو انهيارkotlinx — ignoreUnknownKeys = true
Null في حقل غير قابل للعدمانهيار في وقت التشغيلMoshi — lenient مع @Nullable

تسجيل أخطاء إلغاء التسلسل هو ممارسة إلزامية في الإنتاج. لف decode في do/catch، وسجل JSON الخام ونوع النموذج المتوقع في Crashlytics أو Sentry. هذا سيسمح بتحديد سريع لأي حقل من أي API تعطل وفي أي إصدار من التطبيق. بدون تسجيل، يبدو خطأ إلغاء التسلسل وكأنه انهيار غامض بدون سياق.

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

كيف يختلف إلغاء التسلسل عن التحليل (parsing)؟

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

أي مكتبة إلغاء تسلسل تختار لمشروع Android جديد؟

لمشروع بلغة Kotlin نقية، يُوصى بـ kotlinx.serialization — فهي مدمجة في المترجم، لا تستخدم reflection وتدعم Kotlin Multiplatform. لمشروع Java موجود — Moshi مع code generation. من الأفضل ترك Gson للمشاريع القديمة حيث يتطلب استبداله جهدًا كبيرًا.

ماذا تفعل إذا أرسل الخادم snake_case لكن النموذج يستخدم camelCase؟

على iOS، استخدم keyDecodingStrategy = .convertFromSnakeCase في JSONDecoder. على Android مع kotlinx.serialization، استخدم @SerialName لكل حقل. في Moshi، طبق @Json(name="field_name") أو JsonAdapter.Factory عام. النمط الموحد على مستوى المشروع هو أفضل ممارسة متفق عليها في عقد API.

لماذا يتعطل إلغاء التسلسل في الإنتاج وليس في التطوير؟

السبب الأكثر شيوعًا هو null غير متوقع من الخادم على حقل مُعلن كإلزامي. في التطوير، يعيد الخادم بيانات كاملة؛ في الإنتاج، يعيد ردًا مختصرًا. الحل: وضع علامة قابلية للعدم (nullable) على جميع الحقول التي قد تكون مفقودة في Kotlin أو optional في Swift، واستخدام ignoreUnknownKeys والقيم الافتراضية.

أيهما أسرع — Reflection أم Code generation في إلغاء التسلسل؟

Code generation (Moshi codegen, kotlinx.serialization, Codable) يعمل أسرع بـ 2-4 مرات من reflection في معايير Google. بالإضافة إلى السرعة، توليد الكود أكثر أمانًا من حيث الأنواع، ولا يتطلب بيانات وصفية للفئات في وقت التشغيل، ويتم اكتشاف أخطاء الأنواع في وقت الترجمة وليس أثناء إلغاء التسلسل.

الملخص

  • إلغاء التسلسل هو عملية أساسية في تطوير التطبيقات المحمولة تستعيد كائنًا من JSON أو XML أو Protobuf لاستخدامه في كود التطبيق.
  • iOS يستخدم JSONDecoder مع بروتوكول Codable، مما يوفر تحويلاً تلقائيًا من JSON إلى نموذج مع استراتيجيات المفاتيح والتواريخ.
  • Android يقدم ثلاث أدوات: Gson (reflection)، Moshi (reflection/codegen) و kotlinx.serialization (توليد عن طريق المترجم عبر @Serializable).
  • الأخطاء الشائعة — عدم تطابق النوع، الحقول المفقودة، null في حقول غير قابلة للعدم وعدم توافق إصدارات API — يتم منعها بالأنواع القابلة للعدم و ignoreUnknownKeys وإدارة الإصدارات.
  • Code generation أكثر أمانًا وأسرع من reflection، ولذلك يُوصى بها لإصدارات الإنتاج من التطبيقات المحمولة.
  • استراتيجية التعيين — keyDecodingStrategy على iOS و @SerialName على Android تحل مشكلة عدم تطابق أنماط التسمية بين الخادم والعميل.
  • يجب تسجيل أخطاء إلغاء التسلسل في Crashlytics أو Sentry للتشخيص السريع لحوادث الإنتاج.

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

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

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

اقرأ أيضًا