यदि आपका ऐप अस्थायी रूप से अपना नेटवर्क कनेक्शन खो देता है तो भी फायरबेस एप्लिकेशन काम करते हैं। इसके अलावा, फायरबेस स्थानीय स्तर पर डेटा को बनाए रखने, उपस्थिति को प्रबंधित करने और विलंबता को संभालने के लिए उपकरण प्रदान करता है।
डिस्क दृढ़ता
फायरबेस ऐप्स स्वचालित रूप से अस्थायी नेटवर्क रुकावटों को संभालते हैं। कैश्ड डेटा ऑफ़लाइन होने पर उपलब्ध होता है और नेटवर्क कनेक्टिविटी बहाल होने पर फायरबेस किसी भी राइट को दोबारा भेजता है।
जब आप डिस्क दृढ़ता को सक्षम करते हैं, तो आपका ऐप डिवाइस पर स्थानीय रूप से डेटा लिखता है ताकि आपका ऐप ऑफ़लाइन रहते हुए भी स्थिति बनाए रख सके, भले ही उपयोगकर्ता या ऑपरेटिंग सिस्टम ऐप को पुनरारंभ करता हो।
आप कोड की केवल एक पंक्ति के साथ डिस्क दृढ़ता को सक्षम कर सकते हैं।
तीव्र
Database.database().isPersistenceEnabled = true
उद्देश्य सी
[FIRDatabase database].persistenceEnabled = YES;
दृढ़ता व्यवहार
दृढ़ता को सक्षम करने से, कोई भी डेटा जिसे फायरबेस रीयलटाइम डेटाबेस क्लाइंट ऑनलाइन सिंक करेगा, डिस्क पर बना रहता है और ऑफ़लाइन उपलब्ध होता है, तब भी जब उपयोगकर्ता या ऑपरेटिंग सिस्टम ऐप को पुनरारंभ करता है। इसका मतलब है कि आपका ऐप कैश में संग्रहीत स्थानीय डेटा का उपयोग करके ऑनलाइन काम करता है। स्थानीय अपडेट के लिए श्रोता कॉलबैक चालू रहेंगे।
फायरबेस रीयलटाइम डेटाबेस क्लाइंट स्वचालित रूप से आपके ऐप के ऑफ़लाइन होने पर किए जाने वाले सभी लेखन कार्यों की एक कतार रखता है। जब दृढ़ता सक्षम होती है, तो यह कतार डिस्क पर भी बनी रहती है, इसलिए जब उपयोगकर्ता या ऑपरेटिंग सिस्टम ऐप को पुनरारंभ करता है तो आपके सभी लेख उपलब्ध होते हैं। जब ऐप कनेक्टिविटी पुनः प्राप्त कर लेता है, तो सभी ऑपरेशन फ़ायरबेस रीयलटाइम डेटाबेस सर्वर पर भेज दिए जाते हैं।
यदि आपका ऐप फायरबेस प्रमाणीकरण का उपयोग करता है, तो फायरबेस रीयलटाइम डेटाबेस क्लाइंट ऐप पुनरारंभ होने पर उपयोगकर्ता के प्रमाणीकरण टोकन को जारी रखता है। यदि आपका ऐप ऑफ़लाइन होने पर ऑथ टोकन समाप्त हो जाता है, तो क्लाइंट तब तक लेखन कार्य रोक देता है जब तक कि आपका ऐप उपयोगकर्ता को पुनः प्रमाणित नहीं कर देता, अन्यथा सुरक्षा नियमों के कारण लेखन कार्य विफल हो सकता है।
डेटा ताज़ा रखना
फायरबेस रीयलटाइम डेटाबेस सक्रिय श्रोताओं के लिए डेटा की एक स्थानीय प्रतिलिपि को सिंक्रनाइज़ और संग्रहीत करता है। इसके अलावा, आप विशिष्ट स्थानों को सिंक में रख सकते हैं।
तीव्र
let scoresRef = Database.database().reference(withPath: "scores") scoresRef.keepSynced(true)
उद्देश्य सी
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"]; [scoresRef keepSynced:YES];
फायरबेस रीयलटाइम डेटाबेस क्लाइंट स्वचालित रूप से इन स्थानों पर डेटा डाउनलोड करता है और इसे सिंक में रखता है, भले ही संदर्भ में कोई सक्रिय श्रोता न हो। आप कोड की निम्नलिखित पंक्ति के साथ सिंक्रनाइज़ेशन को वापस बंद कर सकते हैं।
तीव्र
scoresRef.keepSynced(false)
उद्देश्य सी
[scoresRef keepSynced:NO];
डिफ़ॉल्ट रूप से, पहले से सिंक किया गया 10MB डेटा कैश किया जाता है। अधिकांश अनुप्रयोगों के लिए यह पर्याप्त होना चाहिए. यदि कैश अपने कॉन्फ़िगर किए गए आकार से बड़ा हो जाता है, तो फ़ायरबेस रीयलटाइम डेटाबेस उस डेटा को शुद्ध कर देता है जिसका उपयोग हाल ही में कम से कम किया गया है। सिंक में रखा गया डेटा कैश से साफ़ नहीं किया जाता है।
डेटा को ऑफ़लाइन क्वेरी करना
फ़ायरबेस रीयलटाइम डेटाबेस ऑफ़लाइन होने पर उपयोग के लिए क्वेरी से लौटाए गए डेटा को संग्रहीत करता है। ऑफ़लाइन रहते हुए निर्मित प्रश्नों के लिए, फ़ायरबेस रीयलटाइम डेटाबेस पहले से लोड किए गए डेटा के लिए काम करना जारी रखता है। यदि अनुरोधित डेटा लोड नहीं हुआ है, तो फायरबेस रीयलटाइम डेटाबेस स्थानीय कैश से डेटा लोड करता है। जब नेटवर्क कनेक्टिविटी फिर से उपलब्ध होती है, तो डेटा लोड होता है और क्वेरी को प्रतिबिंबित करेगा।
उदाहरण के लिए, यह कोड स्कोर के फायरबेस रीयलटाइम डेटाबेस में अंतिम चार आइटमों के लिए क्वेरी करता है
तीव्र
let scoresRef = Database.database().reference(withPath: "scores") scoresRef.queryOrderedByValue().queryLimited(toLast: 4).observe(.childAdded) { snapshot in print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")") }
उद्देश्य सी
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"]; [[[scoresRef queryOrderedByValue] queryLimitedToLast:4] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) { NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value); }];
मान लें कि उपयोगकर्ता कनेक्शन खो देता है, ऑफ़लाइन हो जाता है, और ऐप को पुनरारंभ करता है। ऑफ़लाइन रहते हुए भी, ऐप एक ही स्थान से अंतिम दो आइटम के लिए क्वेरी करता है। यह क्वेरी अंतिम दो आइटम सफलतापूर्वक लौटा देगी क्योंकि ऐप ने उपरोक्त क्वेरी में सभी चार आइटम लोड कर दिए थे।
तीव्र
scoresRef.queryOrderedByValue().queryLimited(toLast: 2).observe(.childAdded) { snapshot in print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")") }
उद्देश्य सी
[[[scoresRef queryOrderedByValue] queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) { NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value); }];
पिछले उदाहरण में, फायरबेस रीयलटाइम डेटाबेस क्लाइंट लगातार कैश का उपयोग करके उच्चतम स्कोरिंग दो डायनासोर के लिए 'चाइल्ड ऐडेड' इवेंट बढ़ाता है। लेकिन इससे 'वैल्यू' इवेंट नहीं बढ़ेगा, क्योंकि ऐप ने ऑनलाइन रहते हुए कभी भी उस क्वेरी को निष्पादित नहीं किया है।
यदि ऐप ऑफ़लाइन रहते हुए अंतिम छह आइटमों का अनुरोध करता है, तो उसे तुरंत चार कैश्ड आइटमों के लिए 'चाइल्ड ऐडेड' इवेंट मिलेंगे। जब डिवाइस वापस ऑनलाइन आता है, तो फायरबेस रीयलटाइम डेटाबेस क्लाइंट सर्वर के साथ सिंक्रोनाइज़ हो जाता है और ऐप के लिए अंतिम दो 'चाइल्ड ऐडेड' और 'वैल्यू' इवेंट प्राप्त करता है।
लेनदेन को ऑफ़लाइन संभालना
ऐप के ऑफ़लाइन होने पर किया गया कोई भी लेनदेन कतारबद्ध होता है। एक बार जब ऐप नेटवर्क कनेक्टिविटी पुनः प्राप्त कर लेता है, तो लेनदेन रीयलटाइम डेटाबेस सर्वर पर भेज दिया जाता है।
उपस्थिति का प्रबंधन
रीयलटाइम एप्लिकेशन में यह पता लगाना अक्सर उपयोगी होता है कि क्लाइंट कब कनेक्ट होते हैं और कब डिस्कनेक्ट होते हैं। उदाहरण के लिए, जब किसी उपयोगकर्ता का क्लाइंट डिस्कनेक्ट हो जाता है तो आप उसे 'ऑफ़लाइन' के रूप में चिह्नित करना चाह सकते हैं।
फ़ायरबेस डेटाबेस क्लाइंट सरल प्राइमेटिव प्रदान करते हैं जिनका उपयोग आप डेटाबेस में लिखने के लिए कर सकते हैं जब कोई क्लाइंट फ़ायरबेस डेटाबेस सर्वर से डिस्कनेक्ट हो जाता है। ये अपडेट होते हैं चाहे क्लाइंट साफ-साफ डिस्कनेक्ट हो या नहीं, इसलिए कनेक्शन टूटने या क्लाइंट क्रैश होने पर भी आप डेटा को साफ करने के लिए उन पर भरोसा कर सकते हैं। सेटिंग, अपडेट करने और हटाने सहित सभी लेखन कार्य डिस्कनेक्शन पर किए जा सकते हैं।
onDisconnect
प्रिमिटिव का उपयोग करके डिस्कनेक्शन पर डेटा लिखने का एक सरल उदाहरण यहां दिया गया है:
तीव्र
let presenceRef = Database.database().reference(withPath: "disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnectSetValue("I disconnected!")
उद्देश्य सी
FIRDatabaseReference *presenceRef = [[FIRDatabase database] referenceWithPath:@"disconnectmessage"]; // Write a string when this client loses connection [presenceRef onDisconnectSetValue:@"I disconnected!"];
ऑनडिस्कनेक्ट कैसे काम करता है
जब आप onDisconnect()
ऑपरेशन स्थापित करते हैं, तो ऑपरेशन फायरबेस रीयलटाइम डेटाबेस सर्वर पर रहता है। सर्वर यह सुनिश्चित करने के लिए सुरक्षा की जाँच करता है कि उपयोगकर्ता अनुरोधित लेखन कार्यक्रम निष्पादित कर सकता है, और यदि यह अमान्य है तो आपके ऐप को सूचित करता है। सर्वर तब कनेक्शन की निगरानी करता है। यदि किसी भी बिंदु पर कनेक्शन का समय समाप्त हो जाता है, या रीयलटाइम डेटाबेस क्लाइंट द्वारा सक्रिय रूप से बंद कर दिया जाता है, तो सर्वर दूसरी बार सुरक्षा की जांच करता है (यह सुनिश्चित करने के लिए कि ऑपरेशन अभी भी वैध है) और फिर ईवेंट को आमंत्रित करता है।
आपका ऐप राइट ऑपरेशन पर कॉलबैक का उपयोग यह सुनिश्चित करने के लिए कर सकता है कि onDisconnect
सही ढंग से संलग्न था:
तीव्र
presenceRef.onDisconnectRemoveValue { error, reference in if let error = error { print("Could not establish onDisconnect event: \(error)") } }
उद्देश्य सी
[presenceRef onDisconnectRemoveValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *reference) { if (error != nil) { NSLog(@"Could not establish onDisconnect event: %@", error); } }];
onDisconnect
ईवेंट को .cancel()
पर कॉल करके भी रद्द किया जा सकता है:
तीव्र
presenceRef.onDisconnectSetValue("I disconnected") // some time later when we change our minds presenceRef.cancelDisconnectOperations()
उद्देश्य सी
[presenceRef onDisconnectSetValue:@"I disconnected"]; // some time later when we change our minds [presenceRef cancelDisconnectOperations];
कनेक्शन स्थिति का पता लगाना
उपस्थिति-संबंधी कई सुविधाओं के लिए, आपके ऐप के लिए यह जानना उपयोगी है कि वह कब ऑनलाइन या ऑफलाइन है। फायरबेस रीयलटाइम डेटाबेस /.info/connected
पर एक विशेष स्थान प्रदान करता है जिसे हर बार फायरबेस रीयलटाइम डेटाबेस क्लाइंट की कनेक्शन स्थिति बदलने पर अपडेट किया जाता है। यहाँ एक उदाहरण है:
तीव्र
let connectedRef = Database.database().reference(withPath: ".info/connected") connectedRef.observe(.value, with: { snapshot in if snapshot.value as? Bool ?? false { print("Connected") } else { print("Not connected") } })
उद्देश्य सी
FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"]; [connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { if([snapshot.value boolValue]) { NSLog(@"connected"); } else { NSLog(@"not connected"); } }];
/.info/connected
एक बूलियन मान है जो रीयलटाइम डेटाबेस क्लाइंट के बीच सिंक्रनाइज़ नहीं होता है क्योंकि मान क्लाइंट की स्थिति पर निर्भर होता है। दूसरे शब्दों में, यदि एक ग्राहक /.info/connected
को गलत पढ़ता है, तो इसकी कोई गारंटी नहीं है कि एक अलग ग्राहक भी गलत पढ़ेगा।
विलंबता को संभालना
सर्वर टाइमस्टैम्प
फायरबेस रीयलटाइम डेटाबेस सर्वर सर्वर पर उत्पन्न टाइमस्टैम्प को डेटा के रूप में सम्मिलित करने के लिए एक तंत्र प्रदान करते हैं। यह सुविधा, onDisconnect
के साथ मिलकर, उस समय को विश्वसनीय रूप से नोट करने का एक आसान तरीका प्रदान करती है जिस पर रीयलटाइम डेटाबेस क्लाइंट डिस्कनेक्ट हुआ था:
तीव्र
let userLastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline") userLastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())
उद्देश्य सी
FIRDatabaseReference *userLastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"]; [userLastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];
कालद विचलन
जबकि firebase.database.ServerValue.TIMESTAMP
अधिक सटीक है, और अधिकांश पढ़ने/लिखने के संचालन के लिए बेहतर है, यह कभी-कभी फायरबेस रीयलटाइम डेटाबेस के सर्वर के संबंध में क्लाइंट की घड़ी की विषमता का अनुमान लगाने के लिए उपयोगी हो सकता है। आप मिलीसेकंड में मान प्राप्त करने के लिए स्थान /.info/serverTimeOffset
पर कॉलबैक संलग्न कर सकते हैं, जिसे फायरबेस रीयलटाइम डेटाबेस क्लाइंट सर्वर समय का अनुमान लगाने के लिए स्थानीय रिपोर्ट किए गए समय (मिलीसेकंड में युग समय) में जोड़ते हैं। ध्यान दें कि इस ऑफसेट की सटीकता नेटवर्किंग विलंबता से प्रभावित हो सकती है, और इसलिए यह मुख्य रूप से घड़ी के समय में बड़ी (> 1 सेकंड) विसंगतियों की खोज के लिए उपयोगी है।
तीव्र
let offsetRef = Database.database().reference(withPath: ".info/serverTimeOffset") offsetRef.observe(.value, with: { snapshot in if let offset = snapshot.value as? TimeInterval { print("Estimated server time in milliseconds: \(Date().timeIntervalSince1970 * 1000 + offset)") } })
उद्देश्य सी
FIRDatabaseReference *offsetRef = [[FIRDatabase database] referenceWithPath:@".info/serverTimeOffset"]; [offsetRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { NSTimeInterval offset = [(NSNumber *)snapshot.value doubleValue]; NSTimeInterval estimatedServerTimeMs = [[NSDate date] timeIntervalSince1970] * 1000.0 + offset; NSLog(@"Estimated server time: %0.3f", estimatedServerTimeMs); }];
नमूना उपस्थिति ऐप
कनेक्शन स्थिति निगरानी और सर्वर टाइमस्टैम्प के साथ डिस्कनेक्ट संचालन को जोड़कर, आप एक उपयोगकर्ता उपस्थिति प्रणाली बना सकते हैं। इस प्रणाली में, प्रत्येक उपयोगकर्ता यह इंगित करने के लिए डेटाबेस स्थान पर डेटा संग्रहीत करता है कि रीयलटाइम डेटाबेस क्लाइंट ऑनलाइन है या नहीं। ग्राहक ऑनलाइन आने पर इस स्थान को सही पर सेट करते हैं और डिस्कनेक्ट होने पर टाइमस्टैम्प को सेट करते हैं। यह टाइमस्टैम्प इंगित करता है कि दिया गया उपयोगकर्ता आखिरी बार कब ऑनलाइन था।
ध्यान दें कि आपके ऐप को किसी उपयोगकर्ता को ऑनलाइन चिह्नित करने से पहले डिस्कनेक्ट ऑपरेशंस को कतारबद्ध करना चाहिए, ताकि सर्वर पर दोनों कमांड भेजे जाने से पहले क्लाइंट का नेटवर्क कनेक्शन खो जाने की स्थिति में किसी भी दौड़ की स्थिति से बचा जा सके।
यहाँ एक सरल उपयोगकर्ता उपस्थिति प्रणाली है:
तीव्र
// since I can connect from multiple devices, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline let myConnectionsRef = Database.database().reference(withPath: "users/morgan/connections") // stores the timestamp of my last disconnect (the last time I was seen online) let lastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline") let connectedRef = Database.database().reference(withPath: ".info/connected") connectedRef.observe(.value, with: { snapshot in // only handle connection established (or I've reconnected after a loss of connection) guard snapshot.value as? Bool ?? false else { return } // add this device to my connections list let con = myConnectionsRef.childByAutoId() // when this device disconnects, remove it. con.onDisconnectRemoveValue() // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition // where you set the user's presence to true and the client disconnects before the // onDisconnect() operation takes effect, leaving a ghost user. // this value could contain info about the device or a timestamp instead of just true con.setValue(true) // when I disconnect, update the last time I was seen online lastOnlineRef.onDisconnectSetValue(ServerValue.timestamp()) })
उद्देश्य सी
// since I can connect from multiple devices, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline FIRDatabaseReference *myConnectionsRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/connections"]; // stores the timestamp of my last disconnect (the last time I was seen online) FIRDatabaseReference *lastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"]; FIRDatabaseReference *connectedRef = [[FIRDatabase database] referenceWithPath:@".info/connected"]; [connectedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { if([snapshot.value boolValue]) { // connection established (or I've reconnected after a loss of connection) // add this device to my connections list FIRDatabaseReference *con = [myConnectionsRef childByAutoId]; // when this device disconnects, remove it [con onDisconnectRemoveValue]; // The onDisconnect() call is before the call to set() itself. This is to avoid a race condition // where you set the user's presence to true and the client disconnects before the // onDisconnect() operation takes effect, leaving a ghost user. // this value could contain info about the device or a timestamp instead of just true [con setValue:@YES]; // when I disconnect, update the last time I was seen online [lastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]]; } }];