(ज़रूरी नहीं) प्रोटोटाइप बनाना और Firebase Local Emulator Suite की मदद से टेस्ट करना
आपका ऐप्लिकेशन Realtime Database पर किस तरह से डेटा पढ़ता है और उसे कैसे लिखा जाता है, इस बारे में बात करने से पहले, चलिए, कुछ ऐसे टूल के बारे में जानते हैं जिनका इस्तेमाल Realtime Database को प्रोटोटाइप करने और उनकी जांच करने के लिए किया जा सकता है फ़ंक्शन: Firebase Local Emulator Suite. अगर आपको अलग-अलग डेटा मॉडल आज़माने हैं, सुरक्षा नियमों को ऑप्टिमाइज़ करना है या बैक-एंड के साथ इंटरैक्ट करने का सबसे किफ़ायती तरीका ढूंढना है, तो लाइव सेवाओं को डिप्लॉय किए बिना स्थानीय तौर पर काम करना एक अच्छा आइडिया हो सकता है.
एक Realtime Database एम्युलेटर, Local Emulator Suite का हिस्सा है, जो इससे आपका ऐप्लिकेशन, आपके डेटाबेस के एम्युलेट किए गए कॉन्टेंट और कॉन्फ़िगरेशन से इंटरैक्ट कर सकता है. जैसे: विकल्प के तौर पर, आपके एम्युलेट किए गए प्रोजेक्ट रिसोर्स (फ़ंक्शन, अन्य डेटाबेस, और सुरक्षा के नियम शामिल हैं).
Realtime Database एमुलेटर का इस्तेमाल करने के लिए, ये चरण अपनाएं:
- एम्युलेटर से कनेक्ट करने के लिए, अपने ऐप्लिकेशन के टेस्ट कॉन्फ़िगरेशन में कोड की लाइन जोड़ना.
- आपकी लोकल प्रोजेक्ट डायरेक्ट्री के रूट से,
firebase emulators:start
पर चल रहा है. - Realtime Database प्लैटफ़ॉर्म का इस्तेमाल करके, अपने ऐप्लिकेशन के प्रोटोटाइप कोड से कॉल करना हमेशा की तरह SDK टूल या Realtime Database REST API का इस्तेमाल करके इंस्टॉल करें.
Realtime Database और Cloud Functions से जुड़े सिलसिलेवार निर्देश उपलब्ध हैं. आपको Local Emulator Suite के बारे में जानकारी भी देखनी चाहिए.
FIRDatabaseReference पाना
डेटाबेस से डेटा पढ़ने या उसमें बदलाव करने के लिए, आपको के इंस्टेंस की ज़रूरत होगी
FIRDatabaseReference
:
Swift
var ref: DatabaseReference! ref = Database.database().reference()
Objective-C
@property (strong, nonatomic) FIRDatabaseReference *ref; self.ref = [[FIRDatabase database] reference];
डेटा सेव करना
इस दस्तावेज़ में, Firebase डेटा को पढ़ने और उसमें डेटा जोड़ने के बारे में बुनियादी जानकारी दी गई है.
Firebase डेटा को Database
रेफ़रंस में लिखा जाता है और इसे
रेफ़रंस के साथ एसिंक्रोनस लिसनर अटैच करना. लिसनर ट्रिगर हो गया है
एक बार डेटा की शुरुआती स्थिति के लिए और फिर कभी भी डेटा में बदलाव होता है.
डेटा लिखने से जुड़ी बुनियादी कार्रवाइयां
लिखने के बुनियादी काम करने के लिए, setValue
का इस्तेमाल करके किसी खास प्रोजेक्ट में डेटा सेव किया जा सकता है
संदर्भ दिया होता है, जो उस पाथ के किसी भी मौजूदा डेटा को बदल देता है. इस तरीके का इस्तेमाल करके:
- उपलब्ध JSON टाइप के पास के टाइप इस तरह हैं:
NSString
NSNumber
NSDictionary
NSArray
उदाहरण के लिए, setValue
वाले किसी उपयोगकर्ता को इस तरह जोड़ा जा सकता है:
Swift
self.ref.child("users").child(user.uid).setValue(["username": username])
Objective-C
[[[self.ref child:@"users"] child:authResult.user.uid] setValue:@{@"username": username}];
setValue
का इस तरह इस्तेमाल करने से, बताई गई जगह के डेटा को ओवरराइट कर दिया जाता है,
इसमें सभी चाइल्ड नोड शामिल हैं. हालांकि, बच्चे के खाते को इनके बिना भी अपडेट किया जा सकता है
पूरे ऑब्जेक्ट को फिर से लिखना. अगर आपको उपयोगकर्ताओं को उनकी प्रोफ़ाइल अपडेट करने की अनुमति देनी है
तो आप उपयोगकर्ता नाम को इस प्रकार अपडेट कर सकते हैं:
Swift
self.ref.child("users/\(user.uid)/username").setValue(username)
Objective-C
[[[[_ref child:@"users"] child:user.uid] child:@"username"] setValue:username];
डेटा पढ़ें
वैल्यू इवेंट को सुनकर डेटा देखना
पाथ पर डेटा पढ़ने और बदलावों को सुनने के लिए,
निगरानी करने के लिए FIRDatabaseReference
में से observeEventType:withBlock
FIRDataEventTypeValue
इवेंट.
इवेंट प्रकार | सामान्य इस्तेमाल |
---|---|
FIRDataEventTypeValue |
पाथ की पूरी सामग्री में हुए बदलावों को पढ़ और सुन सकता है. |
किसी दिए गए पाथ पर मौजूद डेटा को पढ़ने के लिए, FIRDataEventTypeValue
इवेंट का इस्तेमाल किया जा सकता है, क्योंकि यह इवेंट के समय मौजूद होता है. यह तरीका एक बार ट्रिगर होता है. ऐसा तब होता है, जब
लिसनर को हर बार अटैच किया जाता है. डेटा में, किसी भी बच्चे के डेटा को भी शामिल किया जाता है.
बदलाव. इवेंट कॉलबैक को एक snapshot
पास किया जाता है, जिसमें उसका पूरा डेटा होता है
जगह की जानकारी, जिसमें चाइल्ड डेटा शामिल है. अगर कोई डेटा नहीं है, तो स्नैपशॉट दिखेगा
value
प्रॉपर्टी पढ़ने के बाद, exists()
और nil
को कॉल करने पर false
.
निम्न उदाहरण में सोशल ब्लॉगिंग ऐप्लिकेशन डेटाबेस से एक पोस्ट के बारे में जानकारी:
Swift
refHandle = postRef.observe(DataEventType.value, with: { snapshot in // ... })
Objective-C
_refHandle = [_postRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { NSDictionary *postDict = snapshot.value; // ... }];
सुनने वाले को एक FIRDataSnapshot
मिलता है, जिसमें तय किए गए
डेटाबेस में मौजूद लोकेशन की जानकारी, इवेंट के समय इसकी value
प्रॉपर्टी में मौजूद होती है. आपने लोगों तक पहुंचाया मुफ़्त में
वैल्यू को सही नेटिव टाइप को असाइन कर सकता है, जैसे कि NSDictionary
.
अगर जगह के लिए कोई डेटा मौजूद नहीं है, तो value
nil
है.
डेटा को एक बार पढ़ें
getData() का इस्तेमाल करके एक बार पढ़ें
SDK टूल को डेटाबेस सर्वर के साथ इंटरैक्शन को मैनेज करने के लिए डिज़ाइन किया गया है. इससे कोई फ़र्क़ नहीं पड़ता कि ऐप ऑनलाइन है या ऑफ़लाइन.
आम तौर पर, वैल्यू इवेंट की उन तकनीकों का इस्तेमाल करना चाहिए जिनके बारे में ऊपर बताया गया है. डेटा का इस्तेमाल कर सकता है. वे तकनीक आपके इस्तेमाल और बिलिंग को कम करता है. साथ ही, इन्हें आपके उपयोगकर्ताओं को बेहतरीन सेवा देने के लिए ऑप्टिमाइज़ किया गया है उन्हें ऑनलाइन और ऑफ़लाइन होने का अनुभव मिलता है.
अगर आपको डेटा सिर्फ़ एक बार चाहिए, तो डेटाबेस से डेटा का स्नैपशॉट पाने के लिए, getData()
का इस्तेमाल किया जा सकता है. अगर किसी वजह से getData()
,
तो क्लाइंट लोकल स्टोरेज कैश की जांच करेगा और गड़बड़ी दिखाएगा
का इस्तेमाल करें.
इस उदाहरण में, डेटाबेस से उपयोगकर्ता के सार्वजनिक उपयोगकर्ता नाम को एक बार फिर से पाने का तरीका बताया गया है:
Swift
do { let snapshot = try await ref.child("users/\(uid)/username").getData() let userName = snapshot.value as? String ?? "Unknown" } catch { print(error) }
Objective-C
NSString *userPath = [NSString stringWithFormat:@"users/%@/username", uid]; [[ref child:userPath] getDataWithCompletionBlock:^(NSError * _Nullable error, FIRDataSnapshot * _Nonnull snapshot) { if (error) { NSLog(@"Received an error %@", error); return; } NSString *userName = snapshot.value; }];
getData()
का ग़ैर-ज़रूरी इस्तेमाल करने से बैंडविथ का इस्तेमाल बढ़ सकता है और नुकसान हो सकता है
परफ़ॉर्मेंस का डेटा होता है. इसे रीयलटाइम लिसनर का इस्तेमाल करके रोका जा सकता है, जैसा कि दिखाया गया है
पढ़ें.
ऑब्ज़र्वर की मदद से एक बार डेटा पढ़ें
कुछ मामलों में हो सकता है कि आप लोकल कैश मेमोरी से वैल्यू दिखाना चाहें
वह भी तुरंत अपडेट हो जाएगा. उन में
तो आप observeSingleEventOfType
का इस्तेमाल करके
लोकल डिस्क कैश मेमोरी में सेव होने का विकल्प भी है.
यह उस डेटा के लिए फ़ायदेमंद है जिसे सिर्फ़ एक बार लोड करना होता है और जिसे बार-बार बदलने की ज़रूरत नहीं होती या जिसे सुनने के लिए सक्रिय रूप से सुनने की ज़रूरत नहीं होती. उदाहरण के लिए, पिछले उदाहरणों में दिया गया ब्लॉगिंग ऐप्लिकेशन, इस तरीके का इस्तेमाल करके उपयोगकर्ता की प्रोफ़ाइल को लोड करता है. ऐसा तब होता है, जब उपयोगकर्ता कोई नई पोस्ट लिखना शुरू करता है:
Swift
let userID = Auth.auth().currentUser?.uid ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { snapshot in // Get user value let value = snapshot.value as? NSDictionary let username = value?["username"] as? String ?? "" let user = User(username: username) // ... }) { error in print(error.localizedDescription) }
Objective-C
NSString *userID = [FIRAuth auth].currentUser.uid; [[[_ref child:@"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { // Get user value User *user = [[User alloc] initWithUsername:snapshot.value[@"username"]]; // ... } withCancelBlock:^(NSError * _Nonnull error) { NSLog(@"%@", error.localizedDescription); }];
डेटा अपडेट करना या मिटाना
खास फ़ील्ड अपडेट करें
अन्य को ओवरराइट किए बिना नोड के खास चिल्ड्रेन को एक साथ लिखने के लिए
चाइल्ड नोड के लिए, updateChildValues
तरीके का इस्तेमाल करें.
updateChildValues
को कॉल करते समय, कुंजी के लिए पाथ तय करके, कम लेवल की चाइल्ड वैल्यू अपडेट की जा सकती हैं. अगर डेटा को बढ़ाने के लिए कई जगहों पर सेव किया जाता है
बेहतर है, तो आप इसका इस्तेमाल करके उस डेटा के सभी इंस्टेंस को
डेटा फ़ैन-आउट का विकल्प चुनें. उदाहरण के लिए,
ऐसा हो सकता है कि सोशल ब्लॉगिंग ऐप्लिकेशन आपकी पोस्ट बनाने के साथ-साथ उसे अपडेट करके
हाल की गतिविधि फ़ीड और पोस्ट करने वाले उपयोगकर्ता की गतिविधि फ़ीड. ऐसा करने के लिए,
ब्लॉगिंग ऐप्लिकेशन इस तरह के कोड का इस्तेमाल करता है:
Swift
guard let key = ref.child("posts").childByAutoId().key else { return } let post = ["uid": userID, "author": username, "title": title, "body": body] let childUpdates = ["/posts/\(key)": post, "/user-posts/\(userID)/\(key)/": post] ref.updateChildValues(childUpdates)
Objective-C
NSString *key = [[_ref child:@"posts"] childByAutoId].key; NSDictionary *post = @{@"uid": userID, @"author": username, @"title": title, @"body": body}; NSDictionary *childUpdates = @{[@"/posts/" stringByAppendingString:key]: post, [NSString stringWithFormat:@"/user-posts/%@/%@/", userID, key]: post}; [_ref updateChildValues:childUpdates];
इस उदाहरण में, इसके लिए पोस्ट वाले नोड में एक पोस्ट बनाने के लिए childByAutoId
का इस्तेमाल किया गया है
/posts/$postid
के सभी उपयोगकर्ता और साथ ही साथ कुंजी को
getKey()
. इसके बाद कुंजी का इस्तेमाल उपयोगकर्ता की
/user-posts/$userid/$postid
पर पोस्ट.
इन पाथ का इस्तेमाल करके, updateChildValues
को एक बार कॉल करके, JSON ट्री में एक साथ कई जगहों पर अपडेट किए जा सकते हैं. उदाहरण के लिए, यह उदाहरण दोनों जगहों पर नई पोस्ट कैसे बनाता है. इस तरह से एक साथ अपडेट किए जाते हैं
डेटा ऐटॉमिक हो जाता है: या तो सभी अपडेट सफल होते हैं या सभी अपडेट फ़ेल हो जाते हैं.
'पूरा हो गया' ब्लॉक जोड़ना
अगर आपको यह जानना है कि आपका डेटा कब इंपोर्ट किया गया है, तो
पूरा होने वाला ब्लॉक. setValue
और updateChildValues
, दोनों में एक वैकल्पिक 'पूरा होने का ब्लॉक' होता है. इसे तब कॉल किया जाता है, जब डेटाबेस में डेटा लिखने की प्रोसेस पूरी हो जाती है. इस लिसनर की मदद से, यह ट्रैक किया जा सकता है कि कौनसा डेटा
सेव किया गया है और कौनसा डेटा अब भी सिंक किया जा रहा है. अगर कॉल पूरा नहीं होता है,
लिसनर को गड़बड़ी वाला एक ऑब्जेक्ट पास किया जाता है. इसमें गड़बड़ी होने की वजह बताई जाती है.
Swift
do { try await ref.child("users").child(user.uid).setValue(["username": username]) print("Data saved successfully!") } catch { print("Data could not be saved: \(error).") }
Objective-C
[[[_ref child:@"users"] child:user.uid] setValue:@{@"username": username} withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { if (error) { NSLog(@"Data could not be saved: %@", error); } else { NSLog(@"Data saved successfully."); } }];
डेटा मिटाना
डेटा हटाने का सबसे आसान तरीका removeValue
को
की जगह पर हो सकता है.
किसी अन्य डेटा लिखने के लिए nil
को वैल्यू के तौर पर बताकर भी, डेटा को मिटाया जा सकता है
setValue
या updateChildValues
जैसी कार्रवाई. इस तकनीक का इस्तेमाल करके,
updateChildValues
का इस्तेमाल करके, एक एपीआई कॉल में कई बच्चों के नाम मिटाएं.
लिसनर को अलग करें
जब उपयोगकर्ता किसी तीसरे पक्ष की किसी साइट को
ViewController
. अगर ऑब्ज़र्वर को ठीक से नहीं हटाया गया, तो वह सिंक होता रहेगा
डेटा को लोकल मेमोरी में सेव करना हो. जब ऑब्ज़र्वर की ज़रूरत न हो, तो पास करके उसे हटाएं
removeObserverWithHandle
तरीके से जुड़ी FIRDatabaseHandle
.
किसी पहचान फ़ाइल में कॉलबैक ब्लॉक जोड़ने पर, FIRDatabaseHandle
दिखता है.
इन हैंडल का इस्तेमाल कॉलबैक ब्लॉक को हटाने के लिए किया जा सकता है.
अगर डेटाबेस रेफ़रंस में एक से ज़्यादा लिसनर जोड़े गए हैं, तो हर लिसनर
किसी इवेंट के शुरू होने पर कॉल किया जाता है. उस जगह पर डेटा सिंक होने से रोकने के लिए,
आपको removeAllObservers
पर कॉल करके किसी जगह पर मौजूद सभी ऑब्ज़र्वर को हटाना होगा
तरीका.
लिसनर पर removeObserverWithHandle
या removeAllObservers
को कॉल करने से ऐसा होता है
अपने चाइल्ड नोड पर रजिस्टर किए गए लिसनर को अपने-आप नहीं हटाएं; आपको भी ज़रूरी है कि
उन रेफ़रंस या हैंडल को हटाने के लिए उनका ट्रैक रखें.
डेटा को लेन-देन के तौर पर सेव करें
अगर आपको ऐसे डेटा के साथ काम करना है जो एक साथ होने वाले बदलावों की वजह से खराब हो सकता है, तो ट्रांज़ैक्शन ऑपरेशन का इस्तेमाल करें. जैसे, इंक्रीमेंटल काउंटर. इस ऑपरेशन को दो आर्ग्युमेंट दिए जाते हैं: एक अपडेट फ़ंक्शन और एक वैकल्पिक फ़ंक्शन पूरा कॉलबैक. अपडेट फ़ंक्शन, डेटा की मौजूदा स्थिति को इस तरह लेता है तर्क के साथ हल करता है और वह नई मनचाहा स्थिति देता है, जिसे आप लिखना चाहते हैं.
उदाहरण के लिए, उदाहरण में दिए गए सोशल ब्लॉगिंग ऐप्लिकेशन में, उपयोगकर्ताओं को पोस्ट पर स्टार का निशान लगाएं या हटाएं. साथ ही, किसी पोस्ट को मिले स्टार की संख्या ट्रैक करें इस तरह से:
Swift
ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in if var post = currentData.value as? [String: AnyObject], let uid = Auth.auth().currentUser?.uid { var stars: [String: Bool] stars = post["stars"] as? [String: Bool] ?? [:] var starCount = post["starCount"] as? Int ?? 0 if let _ = stars[uid] { // Unstar the post and remove self from stars starCount -= 1 stars.removeValue(forKey: uid) } else { // Star the post and add self to stars starCount += 1 stars[uid] = true } post["starCount"] = starCount as AnyObject? post["stars"] = stars as AnyObject? // Set value and report transaction success currentData.value = post return TransactionResult.success(withValue: currentData) } return TransactionResult.success(withValue: currentData) }) { error, committed, snapshot in if let error = error { print(error.localizedDescription) } }
Objective-C
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) { NSMutableDictionary *post = currentData.value; if (!post || [post isEqual:[NSNull null]]) { return [FIRTransactionResult successWithValue:currentData]; } NSMutableDictionary *stars = post[@"stars"]; if (!stars) { stars = [[NSMutableDictionary alloc] initWithCapacity:1]; } NSString *uid = [FIRAuth auth].currentUser.uid; int starCount = [post[@"starCount"] intValue]; if (stars[uid]) { // Unstar the post and remove self from stars starCount--; [stars removeObjectForKey:uid]; } else { // Star the post and add self to stars starCount++; stars[uid] = @YES; } post[@"stars"] = stars; post[@"starCount"] = @(starCount); // Set value and report transaction success currentData.value = post; return [FIRTransactionResult successWithValue:currentData]; } andCompletionBlock:^(NSError * _Nullable error, BOOL committed, FIRDataSnapshot * _Nullable snapshot) { // Transaction completed if (error) { NSLog(@"%@", error.localizedDescription); } }];
लेन-देन का इस्तेमाल करने पर, अगर एक से ज़्यादा स्टार दिए गए हैं, तो स्टार काउंट गलत नहीं होगा
उपयोगकर्ताओं ने एक ही समय पर एक ही पोस्ट पर स्टार का निशान लगाया या क्लाइंट के पास पुराना डेटा था. कॉन्टेंट बनाने
FIRMutableData
क्लास में शामिल वैल्यू, शुरुआत में क्लाइंट की आखिरी वैल्यू होती है
पथ के लिए ज्ञात मान या कोई न होने पर nil
. सर्वर, शुरुआती वैल्यू की तुलना उसकी मौजूदा वैल्यू से करता है. अगर वैल्यू मैच होती हैं, तो लेन-देन को स्वीकार कर लिया जाता है. अगर वैल्यू मैच नहीं होती हैं, तो लेन-देन अस्वीकार कर दिया जाता है. अगर ट्रांज़ैक्शन अस्वीकार हो जाता है, तो सर्वर
इससे क्लाइंट के लिए मौजूदा वैल्यू मिलती है, जो
अपडेट किया गया मान. लेन-देन स्वीकार किए जाने या तय सीमा से ज़्यादा बार लेन-देन पूरा होने तक, ऐसा होता रहेगा
कितनी बार कोशिश की जा चुकी है.
ऐटमिक सर्वर-साइड इंक्रीमेंट
ऊपर दिए गए इस्तेमाल के उदाहरण में, हम डेटाबेस में दो वैल्यू लिख रहे हैं: आईडी पोस्ट पर स्टार का निशान लगाने/अनस्टार का निशान लगाने वाले उपयोगकर्ता और बढ़ते हुए स्टार काउंट के बारे में जानकारी. अगर हम अगर उपयोगकर्ता पोस्ट पर स्टार का निशान लगा रहा है, तो हम ऐटोमिक इंक्रीमेंट का इस्तेमाल कर सकते हैं लेन-देन के बजाय कार्रवाई करता है.
Swift
let updates = [ "posts/\(postID)/stars/\(userID)": true, "posts/\(postID)/starCount": ServerValue.increment(1), "user-posts/\(postID)/stars/\(userID)": true, "user-posts/\(postID)/starCount": ServerValue.increment(1) ] as [String : Any] Database.database().reference().updateChildValues(updates)
Objective-C
NSDictionary *updates = @{[NSString stringWithFormat: @"posts/%@/stars/%@", postID, userID]: @TRUE, [NSString stringWithFormat: @"posts/%@/starCount", postID]: [FIRServerValue increment:@1], [NSString stringWithFormat: @"user-posts/%@/stars/%@", postID, userID]: @TRUE, [NSString stringWithFormat: @"user-posts/%@/starCount", postID]: [FIRServerValue increment:@1]}; [[[FIRDatabase database] reference] updateChildValues:updates];
यह कोड, लेन-देन के ऑपरेशन का इस्तेमाल नहीं करता. इसलिए, अगर कोई अपडेट करने से कोई समस्या आती है, तो यह कोड अपने-आप फिर से नहीं चलता. हालांकि, बढ़ोतरी के बाद वाली कार्रवाई डेटाबेस सर्वर पर सीधे किया जाता है, तो किसी तरह के टकराव की संभावना नहीं होती.
अगर आपको ऐप्लिकेशन से जुड़े खास विवादों का पता लगाना और उन्हें अस्वीकार करना है, जैसे कि कोई उपयोगकर्ता जिस पोस्ट को वे पहले ही तारांकित कर चुके हैं, तो आपको अपने के सुरक्षा नियमों को लागू कर दिया है.
डेटा के साथ ऑफ़लाइन काम करना
अगर किसी क्लाइंट का इंटरनेट कनेक्शन बंद हो जाता है, तो आपका ऐप्लिकेशन काम करता रहेगा सही तरीके से.
Firebase डेटाबेस से जुड़े हर क्लाइंट का अपना इंटरनल वर्शन होता है सक्रिय डेटा का एक उदाहरण है. जब डेटा लिखा जाता है, तो वह इस स्थानीय वर्शन में लिखा जाता है चुनें. इसके बाद, Firebase क्लाइंट उस डेटा को रिमोट डेटाबेस के सर्वर और अन्य क्लाइंट के साथ "बेहतरीन तरीके" से सिंक करता है.
इस वजह से, डेटाबेस में मौजूद सभी फ़ंक्शन, लोकल इवेंट को ट्रिगर करते हैं किसी भी तरह का डेटा सर्वर पर सेव किया जाता है. इसका मतलब है कि आपका ऐप्लिकेशन फिर चाहे वह नेटवर्क में लगने वाले समय या कनेक्टिविटी की परवाह किए बिना रिस्पॉन्सिव हो.
कनेक्टिविटी वापस आने के बाद, आपके ऐप्लिकेशन को ज़रूरत के मुताबिक इवेंट दिखाए जाते हैं, ताकि क्लाइंट बिना किसी परेशानी के सर्वर की मौजूदा स्थिति के साथ सिंक हो जाए कोई कस्टम कोड लिखें.
हम ऑफ़लाइन व्यवहार के बारे में ऑनलाइन और ऑफ़लाइन सुविधाओं के बारे में ज़्यादा जानें.