Apple platformlarında Veri Okuma ve Yazma

(İsteğe bağlı) Firebase Local Emulator Suite ile prototip oluşturun ve test edin

Uygulamanızın Realtime Database'den okuma ve yazma işlemleri hakkında konuşmadan önce, Realtime Database işlevselliğini prototiplemek ve test etmek için kullanabileceğiniz bir dizi aracı tanıtalım: Firebase Local Emulator Suite. Farklı veri modelleri deniyor, güvenlik kurallarınızı optimize ediyor veya arka uçla etkileşim kurmanın en uygun maliyetli yolunu bulmaya çalışıyorsanız, canlı hizmetleri dağıtmadan yerel olarak çalışabilmek harika bir fikir olabilir.

Gerçek Zamanlı Veritabanı öykünücüsü, uygulamanızın öykünülmüş veritabanı içeriğiniz ve yapılandırmanızın yanı sıra isteğe bağlı olarak öykünmüş proje kaynaklarınızla (işlevler, diğer veritabanları ve güvenlik kuralları) etkileşime girmesini sağlayan Yerel Öykünücü Paketinin bir parçasıdır.

Gerçek Zamanlı Veritabanı öykünücüsünü kullanmak yalnızca birkaç adımı içerir:

  1. Öykünücüye bağlanmak için uygulamanızın test yapılandırmasına bir kod satırı ekleme.
  2. Yerel proje dizininizin kökünden, çalıştırılan firebase emulators:start .
  3. Her zamanki gibi bir Realtime Database platformu SDK'sı veya Realtime Database REST API kullanarak uygulamanızın prototip kodundan çağrı yapma.

Gerçek Zamanlı Veritabanı ve Bulut İşlevlerini içeren ayrıntılı bir kılavuz mevcuttur. Local Emulator Suite tanıtımına da bir göz atmalısınız.

Bir FIRDatabaseReference alın

Veritabanından veri okumak veya yazmak için bir FIRDatabaseReference örneğine ihtiyacınız vardır:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
var ref: DatabaseReference!

ref = Database.database().reference()

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
@property (strong, nonatomic) FIRDatabaseReference *ref;

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

Veri yaz

Bu belge, Firebase verilerini okuma ve yazmanın temellerini kapsar.

Firebase verileri bir Database referansına yazılır ve referansa eşzamansız bir dinleyici eklenerek alınır. Dinleyici, verilerin ilk durumu için bir kez ve veriler değiştiğinde tekrar tetiklenir.

Temel yazma işlemleri

Temel yazma işlemleri için, verileri belirtilen bir referansa kaydetmek ve bu yoldaki mevcut verileri değiştirmek için setValue kullanabilirsiniz. Bu yöntemi şu amaçlarla kullanabilirsiniz:

  • Mevcut JSON türlerine karşılık gelen geçiş türleri aşağıdaki gibidir:
    • NSString
    • NSNumber
    • NSDictionary
    • NSArray

Örneğin setValue ile bir kullanıcıyı şu şekilde ekleyebilirsiniz:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
self.ref.child("users").child(user.uid).setValue(["username": username])

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
[[[self.ref child:@"users"] child:authResult.user.uid]
    setValue:@{@"username": username}];

setValue bu şekilde kullanılması, alt düğümler de dahil olmak üzere belirtilen konumdaki verilerin üzerine yazar. Ancak yine de tüm nesneyi yeniden yazmadan bir çocuğu güncelleyebilirsiniz. Kullanıcıların profillerini güncellemelerine izin vermek istiyorsanız, kullanıcı adını aşağıdaki gibi güncelleyebilirsiniz:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
self.ref.child("users/\(user.uid)/username").setValue(username)

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
[[[[_ref child:@"users"] child:user.uid] child:@"username"] setValue:username];

Verileri oku

Değer olaylarını dinleyerek verileri okuyun

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için, FIRDataEventTypeValue olaylarını gözlemlemek üzere FIRDatabaseReference observeEventType:withBlock kullanın.

Etkinlik tipi tipik kullanım
FIRDataEventTypeValue Bir yolun tüm içeriğindeki değişiklikleri okuyun ve dinleyin.

Belirli bir yoldaki verileri, olay sırasında var olduğu şekliyle okumak için FIRDataEventTypeValue olayını kullanabilirsiniz. Bu yöntem, dinleyici eklendiğinde bir kez ve alt öğeler de dahil olmak üzere veriler her değiştiğinde tetiklenir. Olay geri araması, alt veriler de dahil olmak üzere o konumdaki tüm verileri içeren bir snapshot iletilir. Veri yoksa, anlık görüntü, exists() ı çağırdığınızda false ve value özelliğini okuduğunuzda nil döndürür.

Aşağıdaki örnek, bir gönderinin ayrıntılarını veritabanından alan bir sosyal blog uygulamasını göstermektedir:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
refHandle = postRef.observe(DataEventType.value, with: { snapshot in
  // ...
})

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
_refHandle = [_postRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
  NSDictionary *postDict = snapshot.value;
  // ...
}];

Dinleyici, value özelliğinde olay anında veritabanında belirtilen konumdaki verileri içeren bir FIRDataSnapshot alır. Değerleri, NSDictionary gibi uygun yerel türe atayabilirsiniz. Konumda hiçbir veri yoksa, value nil .

Verileri bir kez oku

getData() kullanarak bir kez okuyun

SDK, uygulamanız ister çevrimiçi ister çevrimdışı olsun, veritabanı sunucularıyla etkileşimleri yönetmek için tasarlanmıştır.

Genel olarak, arka uçtan veri güncellemelerinden haberdar olmak için verileri okumak üzere yukarıda açıklanan değer olayları tekniklerini kullanmalısınız. Bu teknikler, kullanımınızı ve faturalandırmanızı azaltır ve kullanıcılarınıza çevrimiçi ve çevrimdışı olduklarında en iyi deneyimi sunmak için optimize edilmiştir.

Verilere yalnızca bir kez ihtiyacınız varsa, veritabanından verilerin anlık görüntüsünü almak için getData() kullanabilirsiniz. Herhangi bir nedenle getData() sunucu değerini döndüremezse, istemci yerel depolama önbelleğini inceler ve değer hala bulunamazsa bir hata döndürür.

Aşağıdaki örnek, bir kullanıcının herkese açık kullanıcı adının veritabanından tek seferde alındığını gösterir:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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";
});

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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;
}];

Gereksiz getData() kullanımı, bant genişliği kullanımını artırabilir ve yukarıda gösterildiği gibi gerçek zamanlı bir dinleyici kullanılarak önlenebilecek performans kaybına neden olabilir.

Bir gözlemci ile verileri bir kez okuyun

Bazı durumlarda, sunucuda güncellenmiş bir değer olup olmadığını kontrol etmek yerine, yerel önbellekten gelen değerin hemen döndürülmesini isteyebilirsiniz. Bu gibi durumlarda, yerel disk önbelleğinden verileri hemen almak için observeSingleEventOfType kullanabilirsiniz.

Bu, yalnızca bir kez yüklenmesi gereken ve sık sık değişmesi veya aktif dinleme gerektirmesi beklenmeyen veriler için kullanışlıdır. Örneğin, önceki örneklerde yer alan blog uygulaması, yeni bir gönderi yazmaya başladıklarında bir kullanıcının profilini yüklemek için bu yöntemi kullanır:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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)
}

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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);
}];

Verileri güncelleme veya silme

Belirli alanları güncelle

Diğer alt düğümlerin üzerine yazmadan aynı anda bir düğümün belirli alt öğelerine yazmak için updateChildValues ​​yöntemini kullanın.

updateChildValues ​​öğesini çağırırken, anahtar için bir yol belirterek alt düzey alt değerleri güncelleyebilirsiniz. Veriler daha iyi ölçeklendirmek için birden çok konumda depolanıyorsa, veri yayma özelliğini kullanarak bu verilerin tüm örneklerini güncelleyebilirsiniz. Örneğin, bir sosyal blog uygulaması bir gönderi oluşturmak ve aynı anda bunu en son etkinlik akışına ve gönderen kullanıcının etkinlik akışına güncellemek isteyebilir. Bunu yapmak için, blog uygulaması şuna benzer bir kod kullanır:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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)

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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];

Bu örnek /posts/$postid adresindeki tüm kullanıcılar için gönderileri içeren düğümde bir gönderi oluşturmak ve aynı anda getKey() ile anahtarı almak için childByAutoId kullanır. Anahtar daha sonra kullanıcının /user-posts/$userid/$postid adresindeki gönderilerinde ikinci bir giriş oluşturmak için kullanılabilir.

Bu yolları kullanarak, tek bir updateChildValues ​​çağrısıyla JSON ağacındaki birden çok konumda eşzamanlı güncellemeler gerçekleştirebilirsiniz; örneğin, bu örneğin her iki konumda da yeni gönderiyi nasıl oluşturduğu gibi. Bu şekilde yapılan eşzamanlı güncellemeler atomiktir: ya tüm güncellemeler başarılı olur ya da tüm güncellemeler başarısız olur.

Tamamlama Bloğu Ekle

Verilerinizin ne zaman işlendiğini bilmek istiyorsanız, bir tamamlama bloğu ekleyebilirsiniz. Hem setValue hem de updateChildValues yazma işlemi veritabanına yüklendiğinde çağrılan isteğe bağlı bir tamamlama bloğu alır. Bu dinleyici, hangi verilerin kaydedildiğini ve hangi verilerin hala senkronize edildiğini takip etmek için yararlı olabilir. Çağrı başarısız olursa, dinleyiciye hatanın neden oluştuğunu belirten bir hata nesnesi iletilir.

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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!")
  }
}

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
[[[_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.");
  }
}];

Verileri sil

Verileri silmenin en basit yolu, o verinin konumuna referansla removeValue çağırmaktır.

setValue veya updateChildValues ​​gibi başka bir yazma işleminin değeri olarak nil belirterek de silebilirsiniz. Tek bir API çağrısında birden çok alt öğeyi silmek için bu tekniği updateChildValues ​​ile kullanabilirsiniz.

Dinleyicileri ayırın

Gözlemciler, bir ViewController öğesinden ayrıldığınızda veri eşitlemeyi otomatik olarak durdurmaz. Gözlemci düzgün bir şekilde kaldırılmazsa, verileri yerel bellekle eşitlemeye devam eder. Bir gözlemciye artık gerek kalmadığında, ilişkili FIRDatabaseHandle öğesini removeObserverWithHandle yöntemine geçirerek gözlemciyi kaldırın.

Bir başvuruya geri arama bloğu eklediğinizde, bir FIRDatabaseHandle döndürülür. Bu tutamaçlar, geri arama bloğunu kaldırmak için kullanılabilir.

Bir veritabanı başvurusuna birden fazla dinleyici eklenmişse, bir olay oluşturulduğunda her bir dinleyici çağrılır. O konumdaki veri senkronizasyonunu durdurmak için removeAllObservers yöntemini çağırarak bir konumdaki tüm gözlemcileri kaldırmanız gerekir.

Bir dinleyicide removeObserverWithHandle veya removeAllObservers çağrılması, alt düğümlerinde kayıtlı dinleyicileri otomatik olarak kaldırmaz; kaldırmak için bu referansları veya tutamaçları da takip etmelisiniz.

Verileri işlem olarak kaydet

Artımlı sayaçlar gibi eşzamanlı değişikliklerle bozulabilecek verilerle çalışırken bir işlem işlemi kullanabilirsiniz. Bu işleme iki bağımsız değişken verirsiniz: bir güncelleme işlevi ve isteğe bağlı bir tamamlama geri araması. Güncelleme işlevi, verilerin mevcut durumunu bir argüman olarak alır ve yazmak istediğiniz yeni istenen durumu döndürür.

Örneğin, örnek sosyal blog uygulamasında, kullanıcıların gönderilere yıldız eklemesine ve yıldızları kaldırmasına izin verebilir ve aşağıdaki gibi bir gönderinin kaç yıldız aldığını takip edebilirsiniz:

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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)
  }
}

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
[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);
  }
}];

Bir işlemin kullanılması, birden fazla kullanıcının aynı gönderiye aynı anda yıldız vermesi veya müşterinin eski verileri olması durumunda yıldız sayımlarının yanlış olmasını önler. FIRMutableData sınıfında yer alan değer, başlangıçta istemcinin yol için bilinen son değeridir veya hiç yoksa nil . Sunucu, başlangıç ​​değerini mevcut değeriyle karşılaştırır ve değerler eşleşirse işlemi kabul eder veya reddeder. İşlem reddedilirse sunucu, işlemi güncellenen değerle yeniden çalıştıran istemciye geçerli değeri döndürür. Bu, işlem kabul edilene veya çok fazla girişimde bulunulana kadar tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım durumunda, veritabanına iki değer yazıyoruz: gönderiye yıldız koyan/yıldızı kaldıran kullanıcının kimliği ve artan yıldız sayısı. Bu kullanıcının gönderiyi paylaştığını zaten biliyorsak, işlem yerine atomik bir artış işlemi kullanabiliriz.

Süratli

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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);

Amaç-C

Not: Bu Firebase ürünü, Uygulama Klibi hedefinde mevcut değildir.
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];

Bu kod bir işlem işlemi kullanmaz, bu nedenle çakışan bir güncelleme varsa otomatik olarak yeniden çalıştırılmaz. Ancak artırma işlemi doğrudan veritabanı sunucusunda gerçekleştiği için çakışma ihtimali yoktur.

Bir kullanıcının daha önce yıldız verdiği bir gönderiye yıldız eklemesi gibi uygulamaya özgü çakışmaları algılamak ve reddetmek istiyorsanız, bu kullanım durumu için özel güvenlik kuralları yazmalısınız.

Verilerle çevrimdışı çalışın

Bir istemci ağ bağlantısını kaybederse uygulamanız düzgün çalışmaya devam eder.

Bir Firebase veritabanına bağlı her istemci, tüm etkin verilerin kendi dahili sürümünü korur. Veri yazıldığında, önce bu yerel sürüme yazılır. Firebase istemcisi daha sonra bu verileri uzak veritabanı sunucularıyla ve diğer istemcilerle "en iyi çaba" esasına göre senkronize eder.

Sonuç olarak, veritabanına yapılan tüm yazma işlemleri, herhangi bir veri sunucuya yazılmadan hemen önce yerel olayları tetikler. Bu, uygulamanızın ağ gecikmesinden veya bağlantıdan bağımsız olarak yanıt vermeye devam ettiği anlamına gelir.

Bağlantı yeniden sağlandıktan sonra uygulamanız, herhangi bir özel kod yazmak zorunda kalmadan istemcinin geçerli sunucu durumuyla eşitlenmesi için uygun olay kümesini alır.

Çevrimiçi ve çevrimdışı yetenekler hakkında daha fazla bilgi edinin bölümünde çevrimdışı davranış hakkında daha fazla konuşacağız.

Sonraki adımlar