OOZOU
تواصلوا معنا
العودة إلى المدونة

Enum ونوع مخصص من نوع JSON بدائي

تعلّموا تقنيتين في Codable

18 ديسمبر 2018
4 دقائق للقراءة
Enum ونوع مخصص من نوع JSON بدائي

سنتعلم اليوم حالتين قد تحتاجون إلى التعامل معهما عند العمل مع Codable: تحليل (parsing) الـ Enum، وتحليل نوع مخصص من نوع بدائي مثل string.

Enum

إذا كان للـ enum الخاص بكم raw value يمكن تمثيلها كـ Int أو String (وأظن أن هذا يغطي معظم الحالات)، فيمكننا جعل الـ enum متوافقًا مع Codable بإسناد raw value إليه.

لنفترض أن لديكم كائن JSON كهذا:

{"name": "iOS developer", "status": "open"}
lang-json

يمكنكم إنشاء struct في Swift كهذا:

<pre>struct Job: Codable {
  enum Status: String, Codable {
    case open
    case close
  }
  let name: String
  let status: Status
}
lang-swift

وإذا كان لديكم enum لا يمكن تمثيله كـ String أو Int، فلا يزال بإمكانكم جعله متوافقًا مع Codable ما دامت الـ raw value نفسها متوافقة مع Codable.

نوع مخصص من نوع بدائي

إذا كان لديكم نوع مخصص يمكن اشتقاقه من نوع JSON أساسي، فمثلًا لديكم كائن تُرسل فيه صورة على شكل string مرمّز بـ base64:

{
  "name": "XXX",
  "image": "data:image/png;base64,iVBORw0KGgo......."
}
lang-json

بما أن UIImage غير متوافق مع Codable ولا يمكننا جعله متوافقًا عبر extension، فلدينا طريقتان للتعامل مع ذلك:

  1. إنشاء wrapper class آخر حول هذه الصورة.
struct Base64ImageWrapper: Codable {
    let image: UIImage

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()        
        let base64String = try container.decode(String.self)        
        let components = base64String.split(separator: ",")        
        if components.count != 2 {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Wrong data format")
        }

        let dataString = String(components[1])

        if let dataDecoded = Data(base64Encoded: dataString, options: .ignoreUnknownCharacters),
            let image = UIImage(data: dataDecoded) {
            self.image = image
        } else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Can't initialize image from data string")
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        let data = image.jpegData(compressionQuality: 1)
        let prefix = "data:image/jpeg;base64,"
        guard let base64String = data?.base64EncodedString(options: .lineLength64Characters) else {
            throw EncodingError.invalidValue(image, EncodingError.Context(codingPath: [], debugDescription: "Can't encode image to base64 string."))
        }

        try container.encode(prefix + base64String)
    }
}
lang-swift

يُفترض أن يكون الكود أعلاه مألوفًا لكم، مع فكرة رئيسية واحدة. فبدلًا من:

let values = try decoder.container(keyedBy: CodingKeys.self)
lang-swift

نستخدم:

let container = try decoder.singleValueContainer()
lang-swift

لأننا نتعامل في هذه الحالة مع قيمة بدائية واحدة، وهي string بترميز base64. ثم يمكننا استخدام هذا الـ wrapper بهذه الطريقة:

<pre>struct ModelUsingImageWrapper: Codable {
  let name: String
  let image: Base64ImageWrapper
}
lang-swift
  1. إضافة encode/decode مخصص لـ UIImage في KeyedEncodingContainer:
extension KeyedEncodingContainer {

    mutating func encode(_ value: UIImage,
                         forKey key: KeyedEncodingContainer.Key) throws {

        let imageData = value.jpegData(compressionQuality: 1)
        let prefix = "data:image/jpeg;base64,"        

        guard let base64String = imageData?.base64EncodedString(options: .lineLength64Characters) else {
            throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: "Can't encode image to base64 string."))
        }

        try encode(prefix + base64String, forKey: key)
    }

}

extension KeyedDecodingContainer {

    public func decode(_ type: UIImage.Type, forKey key: KeyedDecodingContainer.Key) throws -> UIImage {
        let base64String = try decode(String.self, forKey: key)

        // data:image/svg+xml;base64,PD.....
        let components = base64String.split(separator: ",")

        if components.count != 2 {
            throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Unsupported format"))
        }

        let dataString = String(components[1])
        if let dataDecoded = Data(base64Encoded: dataString, options: .ignoreUnknownCharacters), let image = UIImage(data: dataDecoded) {
            return image
        } else {
            throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Unsupported format"))
        }
    }

}
lang-swift

ثم استخدامه مع encode وdecode صريحين.

struct ModelUsingKeyedEncodingContainer: Codable {
  let name: String
  let image: UIImage<pre>  enum CodingKeys: String, CodingKey {
    case name
    case image
  }
  public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    image = try container.decode(UIImage.self, forKey: .image)
  }
  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(name, forKey: .name)
    try container.encode(image, forKey: .image)
  }
}
lang-swift

يُفترض أن تكفي هاتان الطريقتان لمعظم حالات الاستخدام لديكم.

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

يتطور المشهد الرقمي بسرعة، وعلى الشركات أن تتكيّف لتواكب الطلب المتزايد على السرعة والكفاءة والمعالجة في الوقت الفعلي.

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد