Swift Codable की मदद से Cloud Firestore डेटा को मैप करें

Swift का Codable API, जिसे Swift 4 में लॉन्च किया गया है. इससे हमें अपने समाचार संगठन के लिए, कंपाइलर की मदद से, सीरियल वाले फ़ॉर्मैट से Swift पर डेटा मैप करना आसान हो जाता है प्रकार.

ऐसा हो सकता है कि आपने वेब एपीआई से अपने ऐप्लिकेशन के डेटा पर डेटा मैप करने के लिए, Codable का इस्तेमाल किया हो में बदल दिया जाता है, लेकिन वह उससे कहीं ज़्यादा सुविधाजनक है.

इस गाइड में, हम यह देखेंगे कि Codable का इस्तेमाल करके, Cloud Firestore से Swift के टाइप तक और इसी तरह से Swift के तरीके.

Cloud Firestore से दस्तावेज़ फ़ेच करने पर, ��पके ऐप्लिकेशन को की/वैल्यू पेयर का डिक्शनरी या शब्दकोश का कलेक्शन, अगर आपने इनमें से किसी कई दस्तावेज़ों को लौटाने वाली संक्रियाएं).

अब, Swift की डिक्शनरी को सीधे तौर पर इस्तेमाल करना जारी रखा जा सकता है और आपके उपयोग के उदाहरण में हो सकने वाली कुछ शानदार सुविधाएं देती हैं. हालांकि, यह तरीका सुरक्षित नहीं है और इसे लागू करना आसान है एट्रिब्यूट के नाम गलत स्पेलिंग से या मैप करना भूल जाने से, गड़बड़ियों को ट्रैक करना मुश्किल होता है नया एट्रिब्यूट, जब आपकी टीम ने नई शानदार सुविधा की जानकारी शिप की पिछला सप्ताह.

इससे पहले, कई डेवलपर ने इन कमियों को दूर करने के लिए ऐसा आसान मैपिंग लेयर लागू करना जिससे उन्हें डिक्शनरी को मैप करने में मदद मिले स्विफ़्ट के टाइप. हालांकि, इनमें से ज़्यादातर कॉन्फ़िगरेशन मैन्युअल तरीके से किए जाते हैं Cloud Firestore दस्तावेज़ों और आपके ऐप्लिकेशन के डेटा मॉडल के टाइप के हिसाब से.

Swift के Codable API के साथ काम करने की वजह से, यह बहुत ज़्यादा आसान:

  • अब आपको कोई भी मैपिंग कोड, मैन्युअल तरीके से लागू नहीं करना होगा.
  • यह तय करना आसान है कि अलग-अलग नाम वाले एट्रिब्यूट को कैसे मैप किया जाए.
  • यह सुविधा कई तरह के Swift के साथ काम करती है.
  • साथ ही, कस्टम टाइप को मैप करने के लिए, सपोर्ट जोड़ना आसान है.
  • सबसे अच्छी बात यह है कि आसान डेटा मॉडल के लिए, आपको मैपिंग कोड भी शामिल करना होगा.

मैपिंग डेटा

Cloud Firestore, उन दस्तावेज़ों में डेटा सेव करता है जिनमें वैल्यू के लिए मैप किया जाता है. फ़ेच करने के लिए के डेटा का इस्तेमाल कर रहे हैं, तो हम DocumentSnapshot.data() को कॉल कर सकते हैं, जो Any के साथ फ़ील्ड के नामों को मैप करने वाला डिक्शनरी देता है: func data() -> [String : Any]?.

��सका मतलब है कि हर फ़ील्ड को ऐक्सेस करने के लिए, हम स्विफ़्ट के सबस्क्रिप्ट सिंटैक्स का इस्तेमाल कर सकते हैं.

import FirebaseFirestore

#warning("DO NOT MAP YOUR DOCUMENTS MANUALLY. USE CODABLE INSTEAD.")
func fetchBook(documentId: String) {
  let docRef = db.collection("books").document(documentId)

  docRef.getDocument { document, error in
    if let error = error as NSError? {
      self.errorMessage = "Error getting document: \(error.localizedDescription)"
    }
    else {
      if let document = document {
        let id = document.documentID
        let data = document.data()
        let title = data?["title"] as? String ?? ""
        let numberOfPages = data?["numberOfPages"] as? Int ?? 0
        let author = data?["author"] as? String ?? ""
        self.book = Book(id:id, title: title, numberOfPages: numberOfPages, author: author)
      }
    }
  }
}

यह कोड समझने में आसान और आसान लगता है, लेकिन यह बहुत नाज़ुक होता है. का रखरखाव करना कठिन होता है और गड़बड़ी की संभावना होती है.

जैसा कि यहां देखा जा सकता है, हम यह अनुमान लगाते हैं कि दस्तावेज़ में किस तरह का डेटा शामिल है. फ़ील्ड. यह जानकारी सही भी हो सकती है और नहीं भी.

याद रखें कि कोई स्कीमा नहीं होता, इसलिए आसानी से नया दस्तावेज़ जोड़ा जा सकता है और फ़ील्ड के लिए कोई दूसरा टाइप चुनें. आप numberOfPages फ़ील्ड के लिए गलती से स्ट्रिंग चुन लेता है, जिससे करने में मदद मिलती है. साथ ही, आपको अपनी मैपिंग भी अपडेट करनी होगी जब भी कोई नया फ़ील्ड जोड़ा जाता है, तो यह काफ़ी जटिल होता है.

साथ ही, हम यह भी नहीं भूल सकते कि हम स्विफ़्ट के मज़बूत टाइप का फ़ायदा ले रहे हैं सिस्टम, जो प्रॉपर्टी की हर प्रॉपर्टी का ����ी ��ाइप ��������ा है Book.

वैसे, Codable क्या है?

Apple के दस्तावेज़ के मुताबिक, Codable एक "ऐसा टाइप है जो खुद को बदल सकता है एक बाहरी प्रतिनिधित्व के लिए बनाया जा सकता है." Codable, एक तरह का उपनाम है और डिकोड किए जा सकने वाले प्रोटोकॉल के लिए. स्विफ़्ट टाइप के साथ प्रोटोकॉल का उपयोग करने के लिए, कंपाइलर किसी इस तरह की एक इंस्टेंस, सीरियल फ़ॉर्मैट से ली गई है, जैसे कि JSON.

किसी किताब का डेटा सेव करने का आसान तरीका कुछ ऐसा दिख सकता है:

struct Book: Codable {
  var title: String
  var numberOfPages: Int
  var author: String
}

यह देखा जा सकता है कि Codable के टाइप की पुष्टि करना बहुत कम मुश्किल है. सिर्फ़ हम प्रोटोकॉल का पालन करना ज़रूरी था; किसी और बदलाव की ज़रूरत नहीं थी.

इसके साथ, हम अब किसी किताब को आसानी से JSON ऑब्जेक्ट में एन्कोड कर सकते हैं:

do {
  let book = Book(title: "The Hitchhiker's Guide to the Galaxy",
                  numberOfPages: 816,
                  author: "Douglas Adams")
  let encoder = JSONEncoder()
  let data = try encoder.encode(book)
} 
catch {
  print("Error when trying to encode book: \(error)")
}

JSON ऑब्जेक्ट को Book इंस्टेंस में डिकोड करने का तरीका:

let decoder = JSONDecoder()
let data = /* fetch data from the network */
let decodedBook = try decoder.decode(Book.self, from: data)

Codable का इस्तेमाल करके, Cloud Firestore दस्तावेज़ों में सामान्य टाइप के साथ और आसानी से मैप करना

Cloud Firestore, डेटा टाइप के बड़े सेट के स���थ काम करता है. इनमें से कुछ भी तरह के डेटा टाइप इस्तेमाल किए जा सकते हैं स्ट्रिंग से नेस्ट किए गए मैप जोड़ सकते हैं. इनमें से ज़्यादातर विकल्प सीधे Swift के बिल्ट-इन ऐप्लिकेशन से जुड़े हैं प्रकार. इससे पहले कि हम इसे इस्तेमाल करें, डेटा टाइप को मैप करने के बारे में जानते हैं ज़्यादा मुश्किल विकल्पों का इस्तेमाल करना चाहिए.

Cloud Firestore दस्तावेज़ों को Swift टाइप पर मैप करने के लिए, यह तरीका अपनाएं:

  1. पक्का करें कि आपने अपने प्रोजेक्ट में FirebaseFirestore फ़्रेमवर्क जोड़ा हो. Google Analytics 4 पर माइग्रेट करने के लिए, Swift Package Manager या CocoaPods ���ें से कोई एक ऐसा किया जा सकता है.
  2. FirebaseFirestore को अपनी Swift फ़ाइल में इंपोर्ट करें.
  3. टाइप को Codable के हिसाब से बनाएं.
  4. (ज़रूरी नहीं, अगर आपको List व्यू में टाइप का इस्तेमाल करना है) id जोड़ें प्रॉपर्टी को अपने टाइप के हिसाब से सेव करना होगा और @DocumentID का इस्तेमाल करके, Cloud Firestore को यह बताना होगा कि इसे दस्तावेज़ आईडी से मैप करें. हम नीचे इसके बारे में ज़्यादा जानकारी देंगे.
  5. किसी दस्तावेज़ के रेफ़रंस को Swift से मैप करने के लिए, documentReference.data(as: ) का इस्तेमाल करें टाइप करें.
  6. Swift टाइप से डेटा को मैप करने के लिए documentReference.setData(from: ) का इस्तेमाल करें Cloud Firestore दस्तावेज़.
  7. (ज़रूरी नहीं, लेकिन हमारा सुझाव है कि) गड़बड़ियों को ठीक करने का सही तरीका लागू करें.

चलिए, अपने Book टाइप को अपडेट करते हैं:

struct Book: Codable {
  @DocumentID var id: String?
  var title: String
  var numberOfPages: Int
  var author: String
}

इस टाइप को पहले से ही कोड किया जा सकता था. इसलिए, हमें सिर्फ़ id प्रॉपर्टी जोड़नी पड़ी और इसकी मदद से @DocumentID प्रॉपर्टी रैपर के साथ एनोटेट कर सकते हैं.

दस्तावेज़ को फ़ेच और मैप करने के लिए, पिछले कोड स्निपेट का इस्तेमाल करके, हम ये काम कर सकते हैं: सभी मैन्युअल मैपिंग कोड को एक लाइन से बदलें:

func fetchBook(documentId: String) {
  let docRef = db.collection("books").document(documentId)

  docRef.getDocument { document, error in
    if let error = error as NSError? {
      self.errorMessage = "Error getting document: \(error.localizedDescription)"
    }
    else {
      if let document = document {
        do {
          self.book = try document.data(as: Book.self)
        }
        catch {
          print(error)
        }
      }
    }
  }
}

दस्तावेज़ के टाइप की जानकारी देकर, इसे ज़्यादा कम शब्दों में लिखा जा सकता है getDocument(as:) पर कॉल कर��े समय. इससे आपके लिए मैपिंग की प्रक्रिया शुरू हो जाएगी और मैप किए गए दस्तावेज़ के साथ Result टाइप दिखाएं या कोई गड़बड़ी होने पर बताएं डिकोड नहीं किया जा सका:

private func fetchBook(documentId: String) {
  let docRef = db.collection("books").document(documentId)
  
  docRef.getDocument(as: Book.self) { result in
    switch result {
    case .success(let book):
      // A Book value was successfully initialized from the DocumentSnapshot.
      self.book = book
      self.errorMessage = nil
    case .failure(let error):
      // A Book value could not be initialized from the DocumentSnapshot.
      self.errorMessage = "Error decoding document: \(error.localizedDescription)"
    }
  }
}

किसी मौजूदा दस्तावेज़ को अपडेट करना, कॉल करने जितना आसान है documentReference.setData(from: ). गड़बड़ियों को ठीक करने की कुछ बुनियादी जानकारी यहां दी गई है Book इंस्टेंस सेव करने के लिए कोड है:

func updateBook(book: Book) {
  if let id = book.id {
    let docRef = db.collection("books").document(id)
    do {
      try docRef.setData(from: book)
    }
    catch {
      print(error)
    }
  }
}

नया दस्तावेज़ जोड़ते समय, Cloud Firestore अपने-आप संभाल लेगा दस्तावेज़ के लिए नया दस्तावेज़ आईडी असाइन करें. यह तब भी काम करता है, जब ऐप्लिकेशन अभी ऑफ़लाइन है.

func addBook(book: Book) {
  let collectionRef = db.collection("books")
  do {
    let newDocReference = try collectionRef.addDocument(from: self.book)
    print("Book stored with new document reference: \(newDocReference)")
  }
  catch {
    print(error)
  }
}

आसान डेटा टाइप को मैप करने के अलावा, Cloud Firestore कई तरह के डेटा के साथ काम करता है में से कुछ स्ट्रक्चर्ड डेटा टाइप हैं. इनका इस्तेमाल इन कामों के लिए किया जा सकता है: किसी दस्तावेज़ में नेस्ट किए गए ऑब्जेक्ट बना सकते हैं.

नेस्ट किए गए कस्टम टाइप

ज़्यादातर एट्रिब्यूट की वैल्यू को हम अपने दस्तावेज़ों में मैप करना चाहते हैं, जैसे कि या लेखक का नाम हो. लेकिन उन मामलों का क्या होगा जब हमें क्या कोई और जटिल ऑब्जेक्ट सेव करना है? उदाहरण के लिए, हो सकता है कि हम इन यूआरएल को का कवर वर्शन चुनें.

Cloud Firestore में ऐसा करने का सबसे आसान तरीका मैप का इस्तेमाल करना है:

Firestore दस्तावेज़ में नेस्ट किए गए कस्टम टाइप को स्टोर करना

इससे जुड़े स्विफ़्ट स्ट्रक्चर को लिखते समय, हम इस बात का इस्तेमाल कर सकते हैं कि Cloud Firestore, यूआरएल के साथ काम करता है — यूआरएल वाले फ़ील्ड को सेव करने पर, यह तब स्ट्रिंग में और इसके विपरीत में बदला जाएगा:

struct CoverImages: Codable {
  var small: URL
  var medium: URL
  var large: URL
}

struct BookWithCoverImages: Codable {
  @DocumentID var id: String?
  var title: String
  var numberOfPages: Int
  var author: String
  var cover: CoverImages?
}

ध्यान दें कि हमनेCoverImages Cloud Firestore दस्तावेज़. कवर प्रॉपर्टी को चालू करें BookWithCoverImages को विकल्प के तौर पर इस्तेमाल करना ज़रूरी नहीं है. हम इस बात को भी समझ सकते हैं कि कुछ हो सकता है कि दस्तावेज़ों में कवर विशेषता न हो.

अगर आपको यह जानना है कि डेटा फ़ेच या अपडेट करने के लिए कोई भी कोड स्निपेट क्यों नहीं है, आपको यह जानकर खुशी होगी कि पढ़ने के लिए कोड को समायोजित करने की कोई आवश् यकता नहीं है या Cloud Firestore से/पर लिखना: ये सभी चीज़ें हमारे जो शुरुआती सेक्शन में लिखा हो.

सरणियां

कभी-कभी, हम किसी दस्तावेज़ में वैल्यू का कलेक्शन सेव करना चाहते हैं. इसकी शैलियां किताब अच्छा उदाहरण है: द हिचहिकर की गाइड टू द गैलेक्सी जैसी किताब कई कैटगरी में आ सकते हैं — इस मामले में "साइंस-फ़ाई" और "कॉमेडी":

Firestore दस्तावेज़ में कलेक्शन स्टोर करना

Cloud Firestore में, हम कलेक्शन की वैल्यू का इस्तेमाल करके इसे मॉडल कर सकते हैं. यह है यह किसी भी कोड किए जा सकने वाले टाइप (जैसे कि String, Int वगैरह) के साथ काम करता है. नीचे दिए गए हमारे Book मॉडल में शैलियों का कलेक्शन जोड़ने का तरीका दिखाता है:

public struct BookWithGenre: Codable {
  @DocumentID var id: String?
  var title: String
  var numberOfPages: Int
  var author: String
  var genres: [String]
}

यह किसी भी कोडेबल टाइप के लिए काम करता है. इसलिए, हम कस्टम टाइप का भी इस्तेमाल कर सकते हैं. कल्पना हम प्रत्येक पुस्तक के लिए टैग की एक सूची संग्रहित करना चाहते हैं. नाम के साथ टैग है, तो हम टैग के रंग को भी संग्रहित करना चाहेंगे, इस तरह:

Firestore दस्तावेज़ में पसंद के मुताबिक टाइप का कलेक्शन स्टोर करना

इस तरह टैग स्टोर करने के लिए, हमें बस Tag निर्देश लागू करना होगा, और इसे कोड करने लायक बनाएं:

struct Tag: Codable, Hashable {
  var title: String
  var color: String
}

इस तरह, हम अपने Book दस्तावेज़ों में Tags के कलेक्शन को सेव कर सकते हैं!

struct BookWithTags: Codable {
  @DocumentID var id: String?
  var title: String
  var numberOfPages: Int
  var author: String
  var tags: [Tag]
}

दस्तावेज़ के आईडी को मैप करने के बारे में कुछ जानकारी

इससे पहले कि हम और टाइप मैप करें, आइए दस्तावेज़ आईडी को मैप करने के बारे में बात करें एक क्षण के लिए.

हमने पिछले कुछ उदाहरणों में, @DocumentID प्रॉपर्टी रैपर का इस्तेमाल किया है हमारे Cloud Firestore दस्तावेज़ों के दस्तावेज़ आईडी को id प्रॉपर्टी में मैप करने के लिए स्विफ़्ट के अलग-अलग टाइप हैं. यह कई कारणों से महत्वपूर्ण है:

  • इससे हमें यह जानने में मदद मिलती है कि अगर उपयोगकर्ता आपके डिवाइस पर बदलाव.
  • SwiftUI के List में एलिमेंट को Identifiable होना ज़रूरी है, ताकि वे अंदर आने पर एलिमेंट को इधर-उधर जाने से रोकें.

यह बताना ज़रूरी है कि @DocumentID के तौर पर मार्क किया गया एट्रिब्यूट दस्तावेज़ को वापस लिखते समय, Cloud Firestore के एन्कोडर की मदद से कोड म���ं बदला गया. यह है क्योंकि दस्तावेज़ का आईडी, दस्तावेज़ का एक एट्रिब्यूट नहीं है — इसलिए उसे दस्तावेज़ पर लिखना एक गलती होगी.

नेस्ट किए गए टाइप के साथ काम करते समय (जैसे, फ़ंक्शन के अंदर Book पर टैग की अरे पहले वाला उदाहरण दिया गया है), तो @DocumentID को जोड़ने की ज़रूरत नहीं है प्रॉपर्टी: नेस्ट की गई प्रॉपर्टी, Cloud Firestore दस्तावेज़ का हिस्सा हैं और अलग दस्तावेज़ न बनाएं. इसलिए, उन्हें दस्तावेज़ आईडी की ज़रूरत नहीं है.

तारीख और समय

Cloud Firestore में एक तरह का डेटा पहले से मौजूद होता है. इसमें तारीख और समय को हैंडल करने की जानकारी होती है और Codable के लिए Cloud Firestore की सहायता की बदौलत, यह काम करना आसान है उनका इस्तेमाल कैसे हो सकता है.

आइए इस दस्तावेज़ पर नज़र डालते हैं, जो सभी लोगों की मां का प्रतिनिधित्व करता है प्रोग्रामिंग लैंग्वेज, एडा की शुरुआत साल 1843 में हुई थी:

Firestore दस्तावेज़ में तारीखें इकट्ठा करना

इस दस्तावेज़ को मैप करने के लिए, Swift टाइप कुछ ऐसा दिख सकता है:

struct ProgrammingLanguage: Codable {
  @DocumentID var id: String?
  var name: String
  var year: Date
}

हम बिना बातचीत किए तारीख और समय के बारे में इस सेक्शन को नहीं छोड़ सकते @ServerTimestamp के बारे में जानकारी. जब बात आती है, तब यह प्रॉपर्टी रैपर अहम भूमिका निभाता है आपके ऐप में टाइमस्टैंप से निपटना.

किसी भी डिस्ट्रिब्यूट किए गए सिस्टम में, हो सकता है कि अलग-अलग सिस्टम की घड़ियां हमेशा पूरी तरह सिंक में नहीं होते हैं. आपको लग सकता है कि यह बहुत बड़ा नहीं है लेकिन कल्पना करें कि ऐसी घड़ी के असर का मतलब कुछ ऐसा होता है जैसे एक समय के लिए स्टॉक ट्रेड सिस्टम: मिलीसेकंड में होने वाले विचलन का नतीजा लाखों डॉलर का लेन-देन किया जा सकता है.

Cloud Firestore, @ServerTimestamp के मार्क किए गए एट्रिब्यूट को हैंडल करता है यह फ़ॉलो करता है: अगर एट्रिब्यूट को स्टोर करने पर वह nil है (addDocument() का इस्तेमाल करके, उदाहरण के लिए), Cloud Firestore मौजूदा सर्वर के साथ फ़ील्ड को भर देगा टाइमस्टैंप को डेटाबेस में लिखते समय. अगर फ़ील्ड nil नहीं है addDocument() या updateData() को कॉल करने पर, Cloud Firestore हट जाएगा विशेषता मान को पहले जैसा नहीं किया गया है. इस तरह से, नीचे दिए गए फ़ील्ड createdAt और lastUpdatedAt.

जियोपॉइंट

हमारे ऐप्लिकेशन में, जियोलोकेशन की जानकारी हर जगह मौजूद होती है. कई रोमांचक सुविधाएं हो सकती हैं उन्हें सेव किया जा सकता है. उदाहरण के लिए, किसी टास्क के लिए जगह की जानकारी सेव करना मददगार हो सकता है इससे आपको किसी टास्क के बारे में याद दिलाने में मदद मिलेगी.

Cloud Firestore में पहले से मौजूद डेटा टाइप GeoPoint है, जो किसी भी जगह का देशांतर और अक्षांश. स्थान को/से तक मैप करने के लिए Cloud Firestore दस्तावेज़ के तौर पर सेव किया गया है, तो हम GeoPoint टाइप का इस्तेमाल कर सकते हैं:

struct Office: Codable {
  @DocumentID var id: String?
  var name: String
  var location: GeoPoint
}

Swift में संबंधित टाइप CLLocationCoordinate2D है और हम मैप कर सकते हैं जिनमें नीचे दी गई कार्रवाई की जा सकती है:

CLLocationCoordinate2D(latitude: office.location.latitude,
                      longitude: office.location.longitude)

लोगों की जगह के हिसाब से दस्तावेज़ों को क्��े���� ����न��� ���� बारे में ज़्यादा जानने के लिए, यहां जाएं समाधान की यह गाइड देखें.

एनम्स

Enums, स्विफ़्ट की उन भाषाओं में से एक है जिन्हें कम रेटिंग दी गई है; उनमें जितनी जानकारी है वह नहीं है. ईनम के सामान्य इस्तेमाल का उदाहरण यह है कि किसी चीज़ की अलग-अलग स्थितियों को मॉडल करना. उदाहरण के लिए, हो सकता है कि हम कोई ऐप्लिकेशन लिख रहे हों भी मिलता है. किसी लेख की स्थिति ट्रैक करने के लिए, हम एक enum Status:

enum Status: String, Codable {
  case draft
  case inReview
  case approved
  case published
}

Cloud Firestore, ईनम के साथ मूल रूप से काम नहीं करता. इसका मतलब है कि यह सेट है), लेकिन हम अब भी इस तथ्य का इस्तेमाल कर सकते हैं कि enum को टाइप किया जा सकता है, और कॉडबल टाइप चुनें. इस उदाहरण में, हमने String को चुना है, जिसका मतलब है सभी enum मानों को स्ट्रिंग में/से मैप किया जाएगा Cloud Firestore दस्तावेज़.

Swift की सुविधा, कस्टम रॉ वैल्यू के साथ काम करती है. इसलिए, हम यह भी तय कर सकते हैं कि किन वैल्यू को का संदर्भ लें. इसलिए, उदाहरण के लिए, अगर हमने Status.inReview मामले को "समीक्षा में है" के तौर पर मार्क किया गया है, तो हम ऊपर दी गई सूची को इस तरह अपडेट कर सकते हैं अनुसरण करता है:

enum Status: String, Codable {
  case draft
  case inReview = "in review"
  case approved
  case published
}

मैपिंग को पसंद के मुताबिक बनाना

कभी-कभी, हम चाहते हैं कि Cloud Firestore दस्तावेज़ों के एट्रिब्यूट के नाम मैप, Swift में मौजूद हमारे डेटा मॉडल में मौजूद प्रॉपर्टी के नाम से मेल नहीं खाता. उदाहरण के लिए, हमारा कोई सहकर्मी Python डेवलपर हो सकता है और उसने अपने सभी एट्रिब्यूट के नाम के लिए दाईं ओर से सांप चुनें.

चिंता न करें: Codable ने हमें इसकी जानकारी दी है!

इस तरह के मामलों में, हम CodingKeys का इस्तेमाल कर सकते हैं. यह एक enum हम कर सकते हैं यह बताने के लिए कि कुछ एट्रिब्यूट कैसे मैप किए जाएंगे, एक कोड किए जा सकने वाले निर्देश में जोड़ें.

इस दस्तावेज़ पर गौर करें:

ONE_cased एट्रिब्यूट के नाम वाला Firestore दस्तावेज़

इस दस्तावेज़ को ऐसे स्ट्रक्चर से मैप करने के लिए जिसमें String टाइप की नाम प्रॉपर्टी है, हम ProgrammingLanguage संरचना में CodingKeys enum जोड़ने की ज़रूरत है और दस्तावेज़ में विशेषता का नाम:

struct ProgrammingLanguage: Codable {
  @DocumentID var id: String?
  var name: String
  var year: Date
  
  enum CodingKeys: String, CodingKey {
    case id
    case name = "language_name"
    case year
  }
}

डिफ़ॉल्ट रूप से, Codable API हमारे Swift टाइप के प्रॉपर्टी नामों का इस्तेमाल इन कामों के लिए करेगा हम जिन Cloud Firestore दस्तावेज़ों की कोशिश कर रहे हैं उनमें एट्रिब्यूट के नाम तय करें को मैप करने के लिए. इसलिए, अगर एट्रिब्यूट के नाम मैच करते हैं, तो आपको CodingKeys हमारे कोडेबल टाइप में बदला जा सकता है. हालांकि, एक बार हम CodingKeys का इस्तेमाल खास टाइप के लिए, हमें उन सभी प्रॉपर्टी के नाम जोड़ने होंगे जिन्हें हम मैप करना चाहते हैं.

ऊपर दिए गए कोड स्निपेट में, हमने एक id प्रॉपर्टी तय की है. SwiftUI List व्यू में आइडेंटिफ़ायर के तौर पर इस्तेमाल करें. अगर हमने इसे CodingKeys, डेटा फ़ेच करते समय इसे मैप नहीं किया जाएगा. इसलिए, यह nil बन जाएगा. इससे List व्यू, पहले दस्तावेज़ से भरा जाएगा.

ऐसी कोई भी प्रॉपर्टी जो इससे जुड़ी CodingKeys की सूची में केस के तौर पर नहीं दी गई है को मैपिंग प्रोसेस के दौरान अनदेखा कर दिया जाएगा. यह तब सुविधाजनक हो सकता है, जब हम खास तौर पर कुछ प्रॉपर्टी को मैप होने से रोकना चाहते हैं.

उदाहरण के लिए, अगर हम reasonWhyILoveThis प्रॉपर्टी को किया जा रहा है, तो हमें बस इसे CodingKeys enum से हटाना है:

struct ProgrammingLanguage: Identifiable, Codable {
  @DocumentID var id: String?
  var name: String
  var year: Date
  var reasonWhyILoveThis: String = ""
  
  enum CodingKeys: String, CodingKey {
    case id
    case name = "language_name"
    case year
  }
}

कभी-कभी हो सकता है कि हम कोड में एक खाली एट्रिब्यूट को वापस लिखना चाहें Cloud Firestore दस्तावेज़. स्विफ़्ट के एक विकल्प के तौर पर, बिना वैल्यू वाला डेटा मौजूद है और Cloud Firestore, null वैल्यू के साथ भी काम करता है. हालांकि, कोड में बदलने के ऐसे वैकल्पिक तरीकों का डिफ़ॉल्ट तरीका है जिसमें nil वैल्यू होती है उन्हें नज़रअंदाज़ किया जा सकता है. @ExplicitNull से हम स्विफ़्ट के बारे में कुछ कंट्रोल कर सकते हैं वैकल्पिक प्रॉपर्टी को एन्कोड करते समय हैंडल किया जाता है: किसी वैकल्पिक प्रॉपर्टी को @ExplicitNull, हम Cloud Firestore को यह बता सकते हैं कि वह इस प्रॉपर्टी को अगर दस्तावेज़ में nil वैल्यू है, तो उसकी वैल्यू शून्य हो जाएगी.

रंगों को मैप करने के लिए कस्टम एन्कोडर और डिकोडर का इस्तेमाल करना

Codable के साथ डेटा मैप करने की हमारी कवरेज के आखिरी विषय के तौर पर, अब हम आपको कस्टम एन्कोडर और डिकोडर शामिल हैं. इस सेक्शन में मूल साइट शामिल नहीं है Cloud Firestore डेटा टाइप, लेकिन कस्टम एन्कोडर और डिकोडर बड़े पैमाने पर काम के हैं ऐप्लिकेशन पर भी लागू किया जा सकता है.

"मैं रंगों को कैसे मैप करूं" डेवलपर के बारे में अक्सर पूछे जाने वाले सवालों में से एक है. न सिर्फ़ Cloud Firestore के लिए, बल्कि Swift और JSON के बीच मैप करने के लिए भी करते हैं. कई समाधान मौजूद हैं, लेकिन ज़्यादातर समाधान JSON, और उनमें से सभी रंगों को एक नेस्ट की गई डिक्शनरी के रूप में मैप करते हैं, जो इसके आरजीबी से मिलकर बना है कॉम्पोनेंट.

ऐसा लगता है कि इससे बेहतर और आसान समाधान उपलब्ध होना चाहिए. हम वेब कलर का इस्तेमाल क्यों नहीं करते (या ज़्यादा सटीक होने के लिए, सीएसएस हेक्स कलर नोटेशन) — इन्हें इस्तेमाल करना आसान है (मुख्य तौर पर सिर्फ़ एक स्ट्रिंग) और ये पारदर्शिता को भी बढ़ावा देते हैं!

Swift Color को उसकी हेक्स वैल्यू पर मैप करने के लिए, हमें Swift बनाना होगा ऐसा एक्सटेंशन जो Codable को Color में जोड़ देता है.

extension Color {

 init(hex: String) {
    let rgba = hex.toRGBA()

    self.init(.sRGB,
              red: Double(rgba.r),
              green: Double(rgba.g),
              blue: Double(rgba.b),
              opacity: Double(rgba.alpha))
    }

    //... (code for translating between hex and RGBA omitted for brevity)

}

extension Color: Codable {
  
  public init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    let hex = try container.decode(String.self)

    self.init(hex: hex)
  }
  
  public func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    try container.encode(toHex)
  }

}

decoder.singleValueContainer() का इस्तेमाल करके, हम String को आरजीबीए कॉम्पोनेंट को नेस्ट किए बिना, Color के बराबर. इसके अलावा, आपके पास ये विकल्प भी हैं आपके ऐप्लिकेशन के वेब यूज़र इंटरफ़ेस (यूआई) में इन वैल्यू का इस्तेमाल करें. इसके लिए, आपको उन्हें फ़ॉर्मैट करने की ज़रूरत नहीं है पहले!

इसके साथ, हम टैग को मैप करने के लिए कोड को अपडेट कर सकते हैं, जिससे रंग को सीधे हमारे ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) कोड में मैन्युअल रूप से मैप करने के बजाय उन्हें सीधे टैग करें:

struct Tag: Codable, Hashable {
  var title: String
  var color: Color
}

struct BookWithTags: Codable {
  @DocumentID var id: String?
  var title: String
  var numberOfPages: Int
  var author: String
  var tags: [Tag]
}

गड़बड़ियों को ठीक करना

ऊपर दिए गए कोड स्निपेट में, हमने जान-बूझकर गड़बड़ियों को कम से कम रखा है, लेकिन प्रोडक्शन ऐप्लिकेशन में, आपको यह पक्का करना होगा कि गड़बड़ियां हैं.

यहां एक कोड स्निपेट दिया गया है, जो आपको किसी भी गड़बड़ी की स्थिति में उसके इस्तेमाल का तरीका बताता है इसमें काम आ सकता है:

class MappingSimpleTypesViewModel: ObservableObject {
  @Published var book: Book = .empty
  @Published var errorMessage: String?
  
  private var db = Firestore.firestore()
  
  func fetchAndMap() {
    fetchBook(documentId: "hitchhiker")
  }
  
  func fetchAndMapNonExisting() {
    fetchBook(documentId: "does-not-exist")
  }
  
  func fetchAndTryMappingInvalidData() {
    fetchBook(documentId: "invalid-data")
  }
  
  private func fetchBook(documentId: String) {
    let docRef = db.collection("books").document(documentId)
    
    docRef.getDocument(as: Book.self) { result in
      switch result {
      case .success(let book):
        // A Book value was successfully initialized from the DocumentSnapshot.
        self.book = book
        self.errorMessage = nil
      case .failure(let error):
        // A Book value could not be initialized from the DocumentSnapshot.
        switch error {
        case DecodingError.typeMismatch(_, let context):
          self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
        case DecodingError.valueNotFound(_, let context):
          self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
        case DecodingError.keyNotFound(_, let context):
          self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
        case DecodingError.dataCorrupted(let key):
          self.errorMessage = "\(error.localizedDescription): \(key)"
        default:
          self.errorMessage = "Error decoding document: \(error.localizedDescription)"
        }
      }
    }
  }
}

लाइव अपडेट में होने वाली गड़बड़ियों को ठीक करना

पिछले कोड स्निपेट में एक दस्तावेज़ होना चाहिए. एक बार डेटा फ़ेच करने के अलावा, Cloud Firestore ने भी तथाकथित स्नैपशॉट का उपयोग करके, आपके ऐप्लिकेशन पर अपडेट रीयल-टाइम में अपडेट करने का समर्थन करता है लिसनर: हम किसी कलेक्शन (या क्वेरी) पर स्नैपशॉट लिसनर को रजिस्टर कर सकते हैं, और जब भी कोई अपडेट होगा, Cloud Firestore हमारे लिसनर को कॉल करेगा.

यहां एक कोड स्निपेट दिया गया है, जिसमें स्नैपशॉट लिसनर, मैप डेटा को रजिस्टर करने का तरीका बताया गया है का इस्तेमाल करके Codable का इस्तेमाल किया जा सकता है और होने वाली किसी भी गड़बड़ी को ठीक किया जा सकता है. यह भी दिखाया गया है कि कलेक्शन का कोई नया दस्तावेज़ होता है. जैसा कि आपको दिखेगा, इसे अपडेट करने की ज़रूरत नहीं है लोकल अरे, मैप किए गए दस्तावेज़ों को अपने पास रखते हैं. ऐसा इसलिए, क्योंकि इस प्रोसेस को ध्यान में रखते हुए का इस्तेमाल, स्नैपशॉट लिसनर में मौजूद कोड के हिसाब से किया जाता है.

class MappingColorsViewModel: ObservableObject {
  @Published var colorEntries = [ColorEntry]()
  @Published var newColor = ColorEntry.empty
  @Published var errorMessage: String?
  
  private var db = Firestore.firestore()
  private var listenerRegistration: ListenerRegistration?
  
  public func unsubscribe() {
    if listenerRegistration != nil {
      listenerRegistration?.remove()
      listenerRegistration = nil
    }
  }
  
  func subscribe() {
    if listenerRegistration == nil {
      listenerRegistration = db.collection("colors")
        .addSnapshotListener { [weak self] (querySnapshot, error) in
          guard let documents = querySnapshot?.documents else {
            self?.errorMessage = "No documents in 'colors' collection"
            return
          }
          
          self?.colorEntries = documents.compactMap { queryDocumentSnapshot in
            let result = Result { try queryDocumentSnapshot.data(as: ColorEntry.self) }
            
            switch result {
            case .success(let colorEntry):
              if let colorEntry = colorEntry {
                // A ColorEntry value was successfully initialized from the DocumentSnapshot.
                self?.errorMessage = nil
                return colorEntry
              }
              else {
                // A nil value was successfully initialized from the DocumentSnapshot,
                // or the DocumentSnapshot was nil.
                self?.errorMessage = "Document doesn't exist."
                return nil
              }
            case .failure(let error):
              // A ColorEntry value could not be initialized from the DocumentSnapshot.
              switch error {
              case DecodingError.typeMismatch(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.valueNotFound(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.keyNotFound(_, let context):
                self?.errorMessage = "\(error.localizedDescription): \(context.debugDescription)"
              case DecodingError.dataCorrupted(let key):
                self?.errorMessage = "\(error.localizedDescription): \(key)"
              default:
                self?.errorMessage = "Error decoding document: \(error.localizedDescription)"
              }
              return nil
            }
          }
        }
    }
  }
  
  func addColorEntry() {
    let collectionRef = db.collection("colors")
    do {
      let newDocReference = try collectionRef.addDocument(from: newColor)
      print("ColorEntry stored with new document reference: \(newDocReference)")
    }
    catch {
      print(error)
    }
  }
}

इस पोस्ट में उपयोग किए गए सभी कोड स्निपेट उस नमूना ऐप्लिकेशन का हिस्सा हैं जिसे आपने GitHub की इस डेटा स्टोर करने की जगह से डाउनलोड किया जा सकता है.

आगे बढ़ें और Codable का इस्तेमाल करें!

Swift का Codable API, Google Analytics 4 प्रॉपर्टी से डेटा मैप करने का एक असरदार और आसान तरीका देता है आपके ऐप्लिकेशन डेटा मॉडल में और उससे सीरियल फ़ॉर्मैट के लिए. इस गाइड में, आपको पता चला है क��� उन ऐप्लिकेशन में इस्तेमाल करना कितना आसान है जो Cloud Firestore का इस्तेमाल डेटास्टोर.

सामान्य डेटा टाइप वाले एक बुनियादी उदाहरण से शुरुआत करते हुए, हम धीरे-धीरे इससे डेटा मॉडल की जटिलता बढ़ गई, ताकि वह डेटा पर भरोसा कर सके हमारे लिए मैपिंग करने के लिए, कोड करने लायक और Firebase लागू करने की प्रोसेस.

Codable के बारे में ज़्यादा जानकारी पाने के लिए, हमारा सुझाव है कि आप ये संसाधन देखें:

हालांकि, हमने मैपिंग के बारे में पूरी जानकारी देने वाली गाइड बनाने की पूरी कोशिश की है Cloud Firestore दस्तावेज़. इनके अलावा और भी दस्तावेज़ हो सकते हैं. हालांकि, इनमें से किसी का भी इस्तेमाल किया जा सकता है अन्य रणनीतियों ��ा ������ोग कर सकत��� ��ैं. ��ीचे दिए गए सुझाव/राय भेजें या शिकायत करें बटन का इस्तेमाल करके, हमें बताएं कि अन्य तरह के डेटा को मैप करने के लिए, किन रणनीतियों का इस्तेमाल किया जाता है Cloud Firestore का डेटा या Swift में मौजूद डेटा दिखाना.

Cloud Firestore के Codable की मदद से काम न करने की कोई वजह नहीं है.