অ্যাপল প্ল্যাটফর্মে অফলাইন ক্ষমতা

আপনার অ্যাপ সাময়িকভাবে নেটওয়ার্ক সংযোগ হারিয়ে ফেললেও Firebase অ্যাপ্লিকেশনগুলি কাজ করে৷ এছাড়াও, ফায়ারবেস স্থানীয়ভাবে ডেটা বজায় রাখা, উপস্থিতি পরিচালনা এবং লেটেন্সি পরিচালনা করার জন্য সরঞ্জাম সরবরাহ করে।

ডিস্কের অধ্যবসায়

Firebase অ্যাপগুলি স্বয়ংক্রিয়ভাবে অস্থায়ী নেটওয়ার্ক বাধাগুলি পরিচালনা করে। অফলাইনে থাকা অবস্থায় ক্যাশ করা ডেটা পাওয়া যায় এবং নেটওয়ার্ক সংযোগ পুনরুদ্ধার করা হলে Firebase যেকোনো লেখা পুনরায় পাঠায়।

আপনি যখন ডিস্কের স্থিরতা সক্ষম করেন, তখন আপনার অ্যাপটি ডিভাইসে স্থানীয়ভাবে ডেটা লেখে যাতে আপনার অ্যাপ অফলাইনে থাকা অবস্থায় স্থিতি বজায় রাখতে পারে, এমনকি ব্যবহারকারী বা অপারেটিং সিস্টেম অ্যাপটি পুনরায় চালু করলেও।

আপনি কোডের একটি লাইন দিয়ে ডিস্কের স্থিরতা সক্ষম করতে পারেন।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
Database.database().isPersistenceEnabled = true

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[FIRDatabase database].persistenceEnabled = YES;

অধ্যবসায় আচরণ

অধ্যবসায় সক্ষম করার মাধ্যমে, Firebase Realtime Database ক্লায়েন্ট অনলাইনে ডিস্কে থাকাকালীন সিঙ্ক করবে এমন যেকোন ডেটা এবং অফলাইনে উপলব্ধ, এমনকি ব্যবহারকারী বা অপারেটিং সিস্টেম অ্যাপটি পুনরায় চালু করলেও। এর অর্থ হল আপনার অ্যাপটি ক্যাশে সঞ্চিত স্থানীয় ডেটা ব্যবহার করে অনলাইনে কাজ করে। স্থানীয় আপডেটের জন্য শ্রোতা কলব্যাক চালু থাকবে।

Firebase Realtime Database ক্লায়েন্ট স্বয়ংক্রিয়ভাবে সমস্ত লেখার ক্রিয়াকলাপের একটি সারি রাখে যা আপনার অ্যাপ অফলাইনে থাকাকালীন সঞ্চালিত হয়। যখন অধ্যবসায় সক্ষম করা হয়, তখন এই সারিটি ডিস্কে স্থির থাকে যাতে ব্যবহারকারী বা অপারেটিং সিস্টেম অ্যাপটি পুনরায় চালু করলে আপনার সমস্ত লেখা উপলব্ধ থাকে। অ্যাপটি কানেক্টিভিটি ফিরে পেলে, সমস্ত ক্রিয়াকলাপ Firebase Realtime Database সার্ভারে পাঠানো হয়।

যদি আপনার অ্যাপ Firebase প্রমাণীকরণ ব্যবহার করে, Firebase Realtime Database ক্লায়েন্ট অ্যাপ রিস্টার্ট জুড়ে ব্যবহারকারীর প্রমাণীকরণ টোকেন বজায় রাখে। আপনার অ্যাপ অফলাইনে থাকাকালীন যদি প্রমাণীকরণ টোকেনের মেয়াদ শেষ হয়ে যায়, ক্লায়েন্ট আপনার অ্যাপ ব্যবহারকারীকে পুনরায় প্রমাণীকরণ না করা পর্যন্ত লেখার ক্রিয়াকলাপ থামিয়ে দেয়, অন্যথায় সুরক্ষা নিয়মের কারণে লেখার ক্রিয়াকলাপ ব্যর্থ হতে পারে।

ডাটা ফ্রেশ রাখা

Firebase Realtime Database সক্রিয় শ্রোতাদের জন্য ডেটার একটি স্থানীয় অনুলিপি সিঙ্ক্রোনাইজ করে এবং সঞ্চয় করে। এছাড়াও, আপনি সুনির্দিষ্ট অবস্থানগুলিকে সিঙ্কে রাখতে পারেন।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
let scoresRef = Database.database().reference(withPath: "scores")
scoresRef.keepSynced(true)

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
FIRDatabaseReference *scoresRef = [[FIRDatabase database] referenceWithPath:@"scores"];
[scoresRef keepSynced:YES];

Firebase Realtime Database ক্লায়েন্ট স্বয়ংক্রিয়ভাবে এই অবস্থানগুলিতে ডেটা ডাউনলোড করে এবং রেফারেন্সের কোনও সক্রিয় শ্রোতা না থাকলেও এটি সিঙ্কে রাখে। আপনি নিম্নলিখিত কোডের লাইন দিয়ে সিঙ্ক্রোনাইজেশন বন্ধ করতে পারেন।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
scoresRef.keepSynced(false)

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[scoresRef keepSynced:NO];

ডিফল্টরূপে, পূর্বে সিঙ্ক করা 10MB ডেটা ক্যাশে করা হয়। এটি বেশিরভাগ অ্যাপ্লিকেশনের জন্য যথেষ্ট হওয়া উচিত। যদি ক্যাশে কনফিগার করা আকারকে ছাড়িয়ে যায়, Firebase Realtime Database এমন ডেটা পরিষ্কার করে যা সম্প্রতি ব্যবহার করা হয়েছে। সিঙ্কে রাখা ডেটা ক্যাশে থেকে পরিষ্কার করা হয় না।

ডেটা অফলাইনে অনুসন্ধান করা হচ্ছে

Firebase Realtime Database অফলাইনে ব্যবহারের জন্য একটি প্রশ্ন থেকে ফিরে আসা ডেটা সঞ্চয় করে। অফলাইন থাকাকালীন তৈরি করা প্রশ্নের জন্য, Firebase Realtime Database পূর্বে লোড করা ডেটার জন্য কাজ করতে থাকে। অনুরোধ করা ডেটা লোড না হলে, Firebase Realtime Database স্থানীয় ক্যাশে থেকে ডেটা লোড করে৷ নেটওয়ার্ক সংযোগ আবার উপলব্ধ হলে, ডেটা লোড হয় এবং ক্যোয়ারী প্রতিফলিত হবে।

উদাহরণস্বরূপ, এই কোডটি স্কোরগুলির একটি Firebase Realtime Database শেষ চারটি আইটেমের জন্য প্রশ্ন করে

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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")")
}

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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);
    }];

অনুমান করুন যে ব্যবহারকারী সংযোগ হারান, অফলাইনে যান এবং অ্যাপটি পুনরায় চালু করেন। অফলাইনে থাকাকালীন, অ্যাপ একই অবস্থান থেকে শেষ দুটি আইটেমের জন্য প্রশ্ন করে। এই ক্যোয়ারীটি সফলভাবে শেষ দুটি আইটেম ফিরিয়ে দেবে কারণ অ্যাপটি উপরের ক্যোয়ারীতে চারটি আইটেম লোড করেছে।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
scoresRef.queryOrderedByValue().queryLimited(toLast: 2).observe(.childAdded) { snapshot in
  print("The \(snapshot.key) dinosaur's score is \(snapshot.value ?? "null")")
}

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[[[scoresRef queryOrderedByValue] queryLimitedToLast:2]
    observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
      NSLog(@"The %@ dinosaur's score is %@", snapshot.key, snapshot.value);
    }];

পূর্ববর্তী উদাহরণে, Firebase Realtime Database ক্লায়েন্ট স্থায়ী ক্যাশে ব্যবহার করে সর্বোচ্চ স্কোরকারী দুটি ডাইনোসরের জন্য 'শিশু যোগ করা' ইভেন্টগুলি উত্থাপন করে। কিন্তু এটি একটি 'মান' ইভেন্ট বাড়াবে না, যেহেতু অ্যাপটি অনলাইনে থাকাকালীন কখনই সেই প্রশ্নটি কার্যকর করেনি।

যদি অ্যাপটি অফলাইনে থাকা অবস্থায় শেষ ছয়টি আইটেম অনুরোধ করে, তাহলে এটি সরাসরি চারটি ক্যাশ করা আইটেমের জন্য 'শিশু যুক্ত' ইভেন্ট পাবে। ডিভাইসটি অনলাইনে ফিরে আসলে, Firebase Realtime Database ক্লায়েন্ট সার্ভারের সাথে সিঙ্ক্রোনাইজ করে এবং অ্যাপের জন্য চূড়ান্ত দুটি 'চাইল্ড অ্যাড' এবং 'মান' ইভেন্ট পায়।

অফলাইনে লেনদেন পরিচালনা করা

অ্যাপটি অফলাইনে থাকাকালীন সঞ্চালিত যেকোনো লেনদেন সারিবদ্ধ। অ্যাপটি একবার নেটওয়ার্ক সংযোগ ফিরে পেলে, লেনদেনগুলি Realtime Database সার্ভারে পাঠানো হয়।

উপস্থিতি পরিচালনা

রিয়েলটাইম অ্যাপ্লিকেশনগুলিতে ক্লায়েন্ট কখন সংযোগ এবং সংযোগ বিচ্ছিন্ন করে তা সনাক্ত করা প্রায়শই দরকারী। উদাহরণস্বরূপ, আপনি একজন ব্যবহারকারীকে 'অফলাইন' হিসাবে চিহ্নিত করতে চাইতে পারেন যখন তাদের ক্লায়েন্ট সংযোগ বিচ্ছিন্ন হয়ে যায়।

ফায়ারবেস ডাটাবেস ক্লায়েন্ট সাধারণ আদিম প্রদান করে যা আপনি ডাটাবেসে লিখতে ব্যবহার করতে পারেন যখন একটি ক্লায়েন্ট ফায়ারবেস ডেটাবেস সার্ভার থেকে সংযোগ বিচ্ছিন্ন করে। ক্লায়েন্ট পরিষ্কারভাবে সংযোগ বিচ্ছিন্ন করুক বা না করুক এই আপডেটগুলি ঘটবে, তাই একটি সংযোগ ড্রপ বা ক্লায়েন্ট ক্র্যাশ হলেও আপনি ডেটা পরিষ্কার করার জন্য তাদের উপর নির্ভর করতে পারেন। সমস্ত লেখার ক্রিয়াকলাপ, সেটিং, আপডেট এবং অপসারণ সহ, সংযোগ বিচ্ছিন্ন করার পরে সঞ্চালিত হতে পারে।

onDisconnect আদিম ব্যবহার করে সংযোগ বিচ্ছিন্ন হওয়ার পরে ডেটা লেখার একটি সহজ উদাহরণ এখানে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
let presenceRef = Database.database().reference(withPath: "disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnectSetValue("I disconnected!")

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
FIRDatabaseReference *presenceRef = [[FIRDatabase database] referenceWithPath:@"disconnectmessage"];
// Write a string when this client loses connection
[presenceRef onDisconnectSetValue:@"I disconnected!"];

কিভাবে অন ডিসকানেক্ট কাজ করে

আপনি একটি onDisconnect() অপারেশন স্থাপন করলে, অপারেশনটি Firebase Realtime Database সার্ভারে থাকে। ব্যবহারকারী অনুরোধ করা লেখার ইভেন্টটি সম্পাদন করতে পারে তা নিশ্চিত করতে সার্ভার নিরাপত্তা পরীক্ষা করে এবং এটি অবৈধ হলে আপনার অ্যাপকে জানায়। সার্ভার তারপর সংযোগ নিরীক্ষণ. যদি কোনো সময়ে সংযোগের সময় শেষ হয়ে যায়, বা Realtime Database ক্লায়েন্ট দ্বারা সক্রিয়ভাবে বন্ধ হয়ে যায়, সার্ভারটি দ্বিতীয়বার নিরাপত্তা পরীক্ষা করে (অপারেশনটি এখনও বৈধ কিনা তা নিশ্চিত করতে) এবং তারপর ইভেন্টটি আহ্বান করে।

onDisconnect সঠিকভাবে সংযুক্ত করা হয়েছে তা নিশ্চিত করতে আপনার অ্যাপটি রাইট অপারেশনে কলব্যাক ব্যবহার করতে পারে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
presenceRef.onDisconnectRemoveValue { error, reference in
  if let error = error {
    print("Could not establish onDisconnect event: \(error)")
  }
}

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[presenceRef onDisconnectRemoveValueWithCompletionBlock:^(NSError *error, FIRDatabaseReference *reference) {
  if (error != nil) {
    NSLog(@"Could not establish onDisconnect event: %@", error);
  }
}];

একটি onDisconnect ইভেন্টও .cancel() কল করে বাতিল করা যেতে পারে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
presenceRef.onDisconnectSetValue("I disconnected")
// some time later when we change our minds
presenceRef.cancelDisconnectOperations()

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
[presenceRef onDisconnectSetValue:@"I disconnected"];
// some time later when we change our minds
[presenceRef cancelDisconnectOperations];

সংযোগের অবস্থা সনাক্ত করা হচ্ছে

উপস্থিতি-সম্পর্কিত অনেক বৈশিষ্ট্যের জন্য, আপনার অ্যাপটি কখন অনলাইন বা অফলাইনে আছে তা জানার জন্য এটি উপযোগী। Firebase Realtime Database /.info/connected এ একটি বিশেষ অবস্থান প্রদান করে যা প্রতিবার Firebase Realtime Database ক্লায়েন্টের সংযোগের অবস্থা পরিবর্তনের সময় আপডেট করা হয়। এখানে একটি উদাহরণ:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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")
  }
})

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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 হল একটি বুলিয়ান মান যা Realtime Database ক্লায়েন্টের মধ্যে সিঙ্ক্রোনাইজ করা হয় না কারণ মানটি ক্লায়েন্টের অবস্থার উপর নির্ভর করে। অন্য কথায়, যদি একজন ক্লায়েন্ট /.info/connected কে মিথ্যা বলে পড়ে, তাহলে আলাদা ক্লায়েন্ট যে মিথ্যা পড়বে তার কোন গ্যারান্টি নেই।

লেটেন্সি হ্যান্ডলিং

সার্ভার টাইমস্ট্যাম্প

Firebase Realtime Database সার্ভারগুলি ডেটা হিসাবে সার্ভারে উত্পন্ন টাইমস্ট্যাম্পগুলি সন্নিবেশ করার জন্য একটি প্রক্রিয়া সরবরাহ করে। এই বৈশিষ্ট্যটি, onDisconnect সাথে মিলিত, একটি Realtime Database ক্লায়েন্ট সংযোগ বিচ্ছিন্ন হওয়ার সময়টি নির্ভরযোগ্যভাবে নোট করার একটি সহজ উপায় প্রদান করে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
let userLastOnlineRef = Database.database().reference(withPath: "users/morgan/lastOnline")
userLastOnlineRef.onDisconnectSetValue(ServerValue.timestamp())

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
FIRDatabaseReference *userLastOnlineRef = [[FIRDatabase database] referenceWithPath:@"users/morgan/lastOnline"];
[userLastOnlineRef onDisconnectSetValue:[FIRServerValue timestamp]];

ঘড়ি Skew

যদিও firebase.database.ServerValue.TIMESTAMP অনেক বেশি নির্ভুল, এবং বেশিরভাগ পঠন/লেখার ক্রিয়াকলাপের জন্য পছন্দনীয়, এটি মাঝে মাঝে Firebase Realtime Database সার্ভারের ক্ষেত্রে ক্লায়েন্টের ঘড়ির তির্যক অনুমান করতে উপযোগী হতে পারে। আপনি অবস্থান /.info/serverTimeOffset এ একটি কলব্যাক সংযুক্ত করতে পারেন মান পেতে, মিলিসেকেন্ডে, যে Firebase Realtime Database ক্লায়েন্টরা সার্ভারের সময় অনুমান করতে স্থানীয় রিপোর্ট করা সময় (মিলিসেকেন্ডে যুগের সময়) যোগ করে। নোট করুন যে এই অফসেটের নির্ভুলতা নেটওয়ার্কিং লেটেন্সি দ্বারা প্রভাবিত হতে পারে, এবং তাই এটি প্রাথমিকভাবে ঘড়ির সময়ের মধ্যে বড় (> 1 সেকেন্ড) অসঙ্গতিগুলি আবিষ্কার করার জন্য দরকারী।

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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)")
  }
})

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
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);
}];

নমুনা উপস্থিতি অ্যাপ

সংযোগের অবস্থা পর্যবেক্ষণ এবং সার্ভার টাইমস্ট্যাম্পের সাথে সংযোগ বিচ্ছিন্ন অপারেশনগুলিকে একত্রিত করে, আপনি একটি ব্যবহারকারীর উপস্থিতি সিস্টেম তৈরি করতে পারেন। এই সিস্টেমে, একটি Realtime Database ক্লায়েন্ট অনলাইন আছে কিনা তা নির্দেশ করার জন্য প্রতিটি ব্যবহারকারী ডেটাবেস অবস্থানে ডেটা সঞ্চয় করে। ক্লায়েন্টরা এই অবস্থানটিকে সত্য হিসাবে সেট করে যখন তারা অনলাইনে আসে এবং একটি টাইমস্ট্যাম্প যখন তারা সংযোগ বিচ্ছিন্ন করে। এই টাইমস্ট্যাম্প নির্দেশ করে যে প্রদত্ত ব্যবহারকারী শেষবার অনলাইনে ছিলেন।

নোট করুন যে ব্যবহারকারীকে অনলাইনে চিহ্নিত করার আগে আপনার অ্যাপটি সংযোগ বিচ্ছিন্ন করার ক্রিয়াকলাপগুলিকে সারিবদ্ধ করা উচিত, উভয় কমান্ড সার্ভারে পাঠানোর আগে ক্লায়েন্টের নেটওয়ার্ক সংযোগ হারিয়ে যাওয়ার ক্ষেত্রে যে কোনও রেস পরিস্থিতি এড়াতে।

এখানে একটি সাধারণ ব্যবহারকারী উপস্থিতি সিস্টেম আছে:

সুইফট

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
// 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())
})

উদ্দেশ্য-C

দ্রষ্টব্য: এই Firebase পণ্যটি অ্যাপ ক্লিপ লক্ষ্যে উপলব্ধ নয়।
// 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]];
  }
}];