อ่านและเขียนข้อมูลบนแพลตฟอร์ม Apple

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

(ไม่บังคับ) ต้นแบบและทดสอบด้วย Firebase Local Emulator Suite

ก่อนที่จะพูดถึงวิธีที่แอปของคุณอ่านและเขียนไปยัง Realtime Database เรามาแนะนำชุดเครื่องมือที่คุณสามารถใช้เพื่อสร้างต้นแบบและทดสอบการทำงานของ Realtime Database: Firebase Local Emulator Suite หากคุณกำลังทดลองใช้โมเดลข้อมูลต่างๆ เพิ่มประสิทธิภาพกฎความปลอดภัย หรือพยายามหาวิธีที่คุ้มค่าที่สุดในการโต้ตอบกับแบ็กเอนด์ ความสามารถในการทำงานในพื้นที่โดยไม่ต้องปรับใช้บริการสดอาจเป็นแนวคิดที่ดี

โปรแกรมจำลองฐานข้อมูลเรียลไทม์เป็นส่วนหนึ่งของ Local Emulator Suite ซึ่งช่วยให้แอปของคุณสามารถโต้ตอบกับเนื้อหาและการกำหนดค่าฐานข้อมูลที่จำลองได้ รวมถึงทรัพยากรโครงการจำลอง (ฟังก์ชัน ฐานข้อมูลอื่นๆ และกฎความปลอดภัย)

การใช้โปรแกรมจำลองฐานข้อมูลเรียลไทม์เกี่ยวข้องกับขั้นตอนเพียงไม่กี่ขั้นตอน:

  1. การเพิ่มบรรทัดโค้ดในการกำหนดค่าการทดสอบของแอปเพื่อเชื่อมต่อกับโปรแกรมจำลอง
  2. จากรูทของไดเร็กทอรีโปรเจ็กต์ในเครื่องของคุณ ให้รัน firebase emulators:start
  3. การโทรจากโค้ดต้นแบบของแอปโดยใช้ SDK แพลตฟอร์ม Realtime Database ตามปกติ หรือใช้ Realtime Database REST API

มี คำแนะนำโดยละเอียดเกี่ยวกับ Realtime Database และ Cloud Functions คุณควรดูการ แนะนำ Local Emulator Suite ด้วย

รับ FIRDatabaseReference

หากต้องการอ่านหรือเขียนข้อมูลจากฐานข้อมูล คุณต้องมีอินสแตนซ์ของ FIRDatabaseReference :

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
var ref: DatabaseReference!

ref = Database.database().reference()

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

เขียนข้อมูล

เอกสารนี้ครอบคลุมพื้นฐานการอ่านและเขียนข้อมูล Firebase

ข้อมูล Firebase ถูกเขียนไปยังการอ้างอิง Database และดึงข้อมูลโดยแนบ Listener แบบอะซิงโครนัสกับข้อมูลอ้างอิง Listener จะถูกทริกเกอร์หนึ่งครั้งสำหรับสถานะเริ่มต้นของข้อมูล และอีกครั้งทุกครั้งที่ข้อมูลเปลี่ยนแปลง

การดำเนินการเขียนขั้นพื้นฐาน

สำหรับการดำเนินการเขียนพื้นฐาน คุณสามารถใช้ setValue เพื่อบันทึกข้อมูลไปยังการอ้างอิงที่ระบุ โดยแทนที่ข้อมูลที่มีอยู่ที่พาธนั้น คุณสามารถใช้วิธีนี้เพื่อ:

  • ประเภท Pass ที่สอดคล้องกับประเภท JSON ที่มีอยู่ดังนี้:
    • NSString
    • NSNumber
    • NSDictionary
    • NSArray

ตัวอย่างเช่น คุณสามารถเพิ่มผู้ใช้ด้วย setValue ได้ดังนี้:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
self.ref.child("users").child(user.uid).setValue(["username": username])

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
[[[self.ref child:@"users"] child:authResult.user.uid]
    setValue:@{@"username": username}];

การใช้ setValue ในลักษณะนี้จะเขียนทับข้อมูลในตำแหน่งที่ระบุ รวมถึงโหนดย่อยใดๆ อย่างไรก็ตาม คุณยังคงสามารถอัปเดตรายการย่อยได้โดยไม่ต้องเขียนใหม่ทั้งวัตถุ หากคุณต้องการอนุญาตให้ผู้ใช้อัปเดตโปรไฟล์ของพวกเขา คุณสามารถอัปเดตชื่อผู้ใช้ได้ดังนี้:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
self.ref.child("users/\(user.uid)/username").setValue(username)

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
[[[[_ref child:@"users"] child:user.uid] child:@"username"] setValue:username];

อ่านข้อมูล

อ่านข้อมูลโดยฟังเหตุการณ์มูลค่า

หากต้องการอ่านข้อมูลที่เส้นทางและรับฟังการเปลี่ยนแปลง ให้ใช้ observeEventType:withBlock ของ FIRDatabaseReference เพื่อสังเกตเหตุการณ์ FIRDataEventTypeValue

ประเภทงาน การใช้งานทั่วไป
FIRDataEventTypeValue อ่านและฟังการเปลี่ยนแปลงเนื้อหาทั้งหมดของเส้นทาง

คุณสามารถใช้เหตุการณ์ FIRDataEventTypeValue เพื่ออ่านข้อมูลในเส้นทางที่กำหนด เนื่องจากมีอยู่ในเวลาที่เกิดเหตุการณ์ วิธีการนี้จะทริกเกอร์หนึ่งครั้งเมื่อมีการแนบผู้ฟัง และอีกครั้งทุกครั้งที่ข้อมูล รวมถึงลูกๆ มีการเปลี่ยนแปลง การเรียกกลับของเหตุการณ์จะถูกส่งผ่านส snapshot อตที่มีข้อมูลทั้งหมด ณ ตำแหน่งนั้น รวมถึงข้อมูลย่อย หากไม่มีข้อมูล สแนปชอตจะคืนค่า false เมื่อคุณเรียกใช้ exists() และ nil เมื่อคุณอ่านคุณสมบัติ value

ตัวอย่างต่อไปนี้สาธิตแอปพลิเคชันบล็อกโซเชียลที่ดึงรายละเอียดของโพสต์จากฐานข้อมูล:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
refHandle = postRef.observe(DataEventType.value, with: { snapshot in
  // ...
})

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
_refHandle = [_postRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  NSDictionary *postDict = snapshot.value;
  // ...
}];

ผู้ฟังได้รับ FIRDataSnapshot ที่มีข้อมูลที่ตำแหน่งที่ระบุในฐานข้อมูล ณ เวลาที่เกิดเหตุการณ์ในคุณสมบัติ value คุณสามารถกำหนดค่าให้กับประเภทเนทีฟที่เหมาะสม เช่น NSDictionary หากไม่มีข้อมูลที่ตำแหน่งนั้น value จะเป็น nil

อ่านข้อมูลครั้งเดียว

อ่านหนึ่งครั้งโดยใช้ getData()

SDK ได้รับการออกแบบมาเพื่อจัดการการโต้ตอบกับเซิร์ฟเวอร์ฐานข้อมูล ไม่ว่าแอปของคุณจะออนไลน์หรือออฟไลน์

โดยทั่วไป คุณควรใช้เทคนิคเหตุการณ์ค่าที่อธิบายข้างต้นเพื่ออ่านข้อมูลเพื่อรับการแจ้งเตือนการอัปเดตข้อมูลจากแบ็กเอนด์ เทคนิคเหล่านี้ลดการใช้งานและการเรียกเก็บเงินของคุณ และได้รับการปรับให้เหมาะสมเพื่อให้ผู้ใช้ของคุณได้รับประสบการณ์ที่ดีที่สุดขณะออนไลน์และออฟไลน์

หากคุณต้องการข้อมูลเพียงครั้งเดียว คุณสามารถใช้ getData() เพื่อรับสแน็ปช็อตของข้อมูลจากฐานข้อมูล ถ้าด้วยเหตุผลใดก็ตาม getData() ไม่สามารถคืนค่าเซิร์ฟเวอร์ได้ ไคลเอ็นต์จะตรวจสอบแคชที่จัดเก็บในตัวเครื่องและส่งคืนข้อผิดพลาดหากไม่พบค่าดังกล่าว

ตัวอย่างต่อไปนี้สาธิตการดึงชื่อผู้ใช้ที่เปิดเผยต่อสาธารณะของผู้ใช้ในครั้งเดียวจากฐานข้อมูล:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
ref.child("users/\(uid)/username").getData(completion:  { error, snapshot in
  guard error == nil else {
    print(error!.localizedDescription)
    return;
  }
  let userName = snapshot.value as? String ?? "Unknown";
});

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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)
}

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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 ​​คุณสามารถอัปเดตค่าลูกระดับล่างได้โดยการระบุเส้นทางสำหรับคีย์ หากข้อมูลถูกจัดเก็บไว้ในหลายตำแหน่งเพื่อให้ปรับขนาดได้ดีขึ้น คุณสามารถอัปเดตอินสแตนซ์ทั้งหมดของข้อมูลนั้นได้โดยใช้ data fan-out ตัวอย่างเช่น แอปบล็อกโซเชียลอาจต้องการสร้างโพสต์และอัปเดตเป็นฟีดกิจกรรมล่าสุดและฟีดกิจกรรมของผู้ใช้ที่โพสต์พร้อมกัน ในการดำเนินการนี้ แอปพลิเคชันบล็อกจะใช้โค้ดดังนี้:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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)

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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

เมื่อใช้เส้นทางเหล่านี้ คุณสามารถทำการอัปเดตสถานที่หลายแห่งพร้อมกันในแผนผัง JSON ได้พร้อมกันด้วยการเรียก updateChildValues ​​เพียงครั้งเดียว เช่น วิธีที่ตัวอย่างนี้สร้างโพสต์ใหม่ในทั้งสองตำแหน่ง การอัปเดตพร้อมกันในลักษณะนี้เป็นแบบอะตอมมิก: การอัปเดตทั้งหมดสำเร็จหรือการอัปเดตทั้งหมดล้มเหลว

เพิ่มบล็อกสำเร็จ

หากคุณต้องการทราบว่าข้อมูลของคุณได้รับการคอมมิตเมื่อใด คุณสามารถเพิ่มบล็อกการเสร็จสิ้นได้ ทั้ง setValue และ updateChildValues ​​ใช้บล็อกการสำเร็จที่เป็นทางเลือกซึ่งถูกเรียกเมื่อการเขียนได้รับการคอมมิตกับฐานข้อมูล Listener นี้สามารถเป็นประโยชน์ในการติดตามว่าข้อมูลใดได้รับการบันทึกและข้อมูลใดที่ยังคงซิงโครไนซ์อยู่ หากการโทรไม่สำเร็จ Listener จะถูกส่งผ่านอ็อบเจ็กต์ข้อผิดพลาดที่ระบุว่าเหตุใดจึงเกิดความล้มเหลว

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
ref.child("users").child(user.uid).setValue(["username": username]) {
  (error:Error?, ref:DatabaseReference) in
  if let error = error {
    print("Data could not be saved: \(error).")
  } else {
    print("Data saved successfully!")
  }
}

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
[[[_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 ​​เพื่อลบรายการย่อยหลายรายการในการเรียก API ครั้งเดียว

แยกผู้ฟัง

ผู้สังเกตการณ์จะไม่หยุดการซิงค์ข้อมูลโดยอัตโนมัติเมื่อคุณออกจาก ViewController หากผู้สังเกตการณ์ไม่ถูกลบออกอย่างถูกต้อง ผู้สังเกตการณ์จะซิงค์ข้อมูลกับหน่วยความจำภายในเครื่องต่อไป เมื่อไม่ต้องการผู้สังเกตการณ์อีกต่อไป ให้ลบออกโดยส่ง FIRDatabaseHandle ที่เกี่ยวข้องไปยังเมธอด removeObserverWithHandle

เมื่อคุณเพิ่มบล็อกการเรียกกลับในการอ้างอิง FIRDatabaseHandle จะถูกส่งกลับ แฮนเดิลเหล่านี้สามารถใช้เพื่อลบบล็อกการโทรกลับ

หากมีการเพิ่มผู้ฟังหลายรายในการอ้างอิงฐานข้อมูล ผู้ฟังแต่ละคนจะถูกเรียกเมื่อมีเหตุการณ์เกิดขึ้น ในการหยุดการซิงค์ข้อมูลที่ตำแหน่งนั้น คุณต้องลบผู้สังเกตการณ์ทั้งหมดที่ตำแหน่งนั้นออกโดยการเรียกเมธอด removeAllObservers

การเรียก removeObserverWithHandle หรือ removeAllObservers บน listener จะไม่ลบ listeners ที่ลงทะเบียนบนโหนดย่อยโดยอัตโนมัติ คุณต้องติดตามการอ้างอิงหรือหมายเลขอ้างอิงเหล่านั้นเพื่อลบออก

บันทึกข้อมูลเป็นธุรกรรม

เมื่อทำงานกับข้อมูลที่อาจเสียหายจากการแก้ไขพร้อมกัน เช่น ตัวนับที่เพิ่มขึ้น คุณสามารถใช้ การดำเนินการธุรกรรม คุณให้การดำเนินการนี้สองอาร์กิวเมนต์: ฟังก์ชันการอัพเดตและการเรียกกลับที่สมบูรณ์ซึ่งเป็นทางเลือก ฟังก์ชันอัปเดตใช้สถานะปัจจุบันของข้อมูลเป็นอาร์กิวเมนต์ และส่งกลับสถานะใหม่ที่คุณต้องการจะเขียน

ตัวอย่างเช่น ในแอปบล็อกโซเชียลตัวอย่าง คุณสามารถอนุญาตให้ผู้ใช้ติดดาวและเลิกติดดาวโพสต์ และติดตามจำนวนดาวที่โพสต์ได้รับดังนี้:

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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)
  }
}

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
[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 หากไม่มี เซิร์ฟเวอร์จะเปรียบเทียบค่าเริ่มต้นกับมูลค่าปัจจุบันและยอมรับธุรกรรมหากค่าตรงกันหรือปฏิเสธ หากธุรกรรมถูกปฏิเสธ เซิร์ฟเวอร์จะส่งคืนค่าปัจจุบันไปยังไคลเอนต์ ซึ่งรันธุรกรรมอีกครั้งด้วยค่าที่อัพเดต สิ่งนี้จะเกิดขึ้นซ้ำๆ จนกว่าธุรกรรมจะได้รับการยอมรับหรือมีการพยายามหลายครั้งเกินไป

Atomic Server-side เพิ่มขึ้น

ในกรณีการใช้งานข้างต้น เรากำลังเขียนค่าสองค่าลงในฐานข้อมูล: ID ของผู้ใช้ที่ติดดาว/เลิกติดดาวโพสต์ และจำนวนดาวที่เพิ่มขึ้น หากเราทราบแล้วว่าผู้ใช้กำลังติดดาวโพสต์ เราสามารถใช้การดำเนินการ atomic increment แทนการทำธุรกรรม

Swift

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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);

วัตถุประสงค์-C

หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่มีในเป้าหมาย App Clip
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 จะซิงโครไนซ์ข้อมูลนั้นกับเซิร์ฟเวอร์ฐานข้อมูลระยะไกลและกับไคลเอนต์อื่น ๆ ด้วย "ความพยายามอย่างดีที่สุด"

ด้วยเหตุนี้ การเขียนทั้งหมดไปยังฐานข้อมูลจะทริกเกอร์เหตุการณ์ในเครื่องทันที ก่อนที่ข้อมูลใดๆ จะถูกเขียนไปยังเซิร์ฟเวอร์ ซึ่งหมายความว่าแอปของคุณยังคงตอบสนองโดยไม่คำนึงถึงเวลาแฝงของเครือข่ายหรือการเชื่อมต่อ

เมื่อสร้างการเชื่อมต่อขึ้นใหม่แล้ว แอปของคุณจะได้รับชุดเหตุการณ์ที่เหมาะสม เพื่อให้ไคลเอ็นต์ซิงค์กับสถานะเซิร์ฟเวอร์ปัจจุบัน โดยไม่ต้องเขียนโค้ดที่กำหนดเองใดๆ

เราจะพูดถึงพฤติกรรมออฟไลน์เพิ่มเติมใน เรียนรู้เพิ่มเติม เกี่ยวกับความสามารถออนไลน์และออฟไลน์

ขั้นตอนถัดไป