xamarin.iOS ile iCloud kullanma

iOS 5'teki iCloud depolama API'si, uygulamaların kullanıcı belgelerini ve uygulamaya özgü verileri merkezi bir konuma kaydetmesine ve bu öğelere kullanıcının tüm cihazlarından erişmesine olanak tanır.

Dört tür depolama alanı vardır:

  • Anahtar-Değer depolaması - kullanıcının diğer cihazlarında uygulamanızla küçük miktarlarda veri paylaşmak için.

  • UIDocument depolama - UIDocument'ın alt sınıfını kullanarak belgeleri ve diğer verileri kullanıcının iCloud hesabında depolamak için.

  • CoreData - SQLite veritabanı depolama alanı.

  • Tek tek dosyalar ve dizinler - çok sayıda farklı dosyayı doğrudan dosya sisteminde yönetmek için.

Bu belgede ilk iki tür (Anahtar-Değer çiftleri ve UIDocument alt sınıfları) ve Xamarin.iOS'ta bu özelliklerin nasıl kullanılacağı açıklanır.

Gereksinimler

  • Xamarin.iOS'un en son kararlı sürümü
  • Xcode 10
  • Mac için Visual Studio veya Visual Studio 2019.

iCloud geliştirmeye hazırlanma

Uygulamalar hem Apple Sağlama Portalı'nda hem de projenin kendisinde iCloud kullanacak şekilde yapılandırılmalıdır. iCloud için geliştirmeden önce (veya örnekleri denemeden) önce aşağıdaki adımları izleyin.

Bir uygulamayı iCloud'a erişecek şekilde doğru yapılandırmak için:

  • TeamID'nizi bulun - developer.apple.com oturum açın ve Ekip Kimliğinizi (veya tek geliştiriciler için Bireysel Kimliği) almak için Üye Merkezi > Hesabınız > Geliştirici Hesabı Özeti'ni ziyaret edin. 10 karakterlik bir dize ( örneğin A93A5CM278 ) olacaktır. Bu, "kapsayıcı tanımlayıcısının" bir parçasını oluşturur.

  • Yeni uygulama kimliği oluşturma - Uygulama kimliği oluşturmak için Cihaz Sağlama kılavuzunun Mağaza Teknolojileri için Sağlama bölümünde açıklanan adımları izleyin ve iCloud'u izin verilen bir hizmet olarak denetlemeyi unutmayın:

İzin verilen bir hizmet olarak iCloud'a göz atın

  • Yeni sağlama profili oluşturma - Sağlama Profili oluşturmak için Cihaz Sağlama kılavuzunda özetlenen adımları izleyin.

  • Kapsayıcı Tanımlayıcısı'nı Entitlements.plist'e ekleyin; kapsayıcı tanımlayıcı biçimi şeklindedir TeamID.BundleID. Daha fazla bilgi için Yetkilendirmelerle çalışma kılavuzuna bakın.

  • Proje özelliklerini yapılandırma - Info.plist dosyasında, Uygulama Kimliği oluştururken Paket Tanımlayıcısının Paket Kimliği kümesiyle eşleştiğinden emin olun; iOS Paket İmzalama, iCloud App Service ve Özel Yetkilendirmeler dosyasının seçili olduğu bir Uygulama Kimliği içeren bir Sağlama Profili kullanır. Bunların tümü Proje Özellikleri bölmesinin altındaki Visual Studio'da yapılabilir.

  • Cihazınızda iCloud'un etkinleştirilmesi - Ayarlar > iCloud'a gidin ve cihazın oturum açtığından emin olun. Belgeler ve Veriler seçeneğini belirleyin ve açın.

  • iCloud'ı test etmek için bir cihaz kullanmanız gerekir- Simülatör'de çalışmaz. Aslında, iCloud'u çalışır durumda görmek için hepsi aynı Apple kimliğiyle oturum açmış iki veya daha fazla cihaza ihtiyacınız vardır.

Anahtar-Değer Depolama

Anahtar-değer depolama, bir kullanıcının kitap veya dergide görüntülediği son sayfa gibi cihazlarda kalıcı hale geldiğini düşünebileceği az miktarda veriye yöneliktir. Anahtar-değer depolama, verileri yedeklemek için kullanılmamalıdır.

Anahtar-değer depolama kullanılırken dikkat edilmesi gereken bazı sınırlamalar vardır:

  • En büyük anahtar boyutu - Anahtar adları 64 bayttan uzun olamaz.

  • En büyük değer boyutu - Tek bir değerde 64 kilobayttan fazla depolayamazsınız.

  • Bir uygulama için en büyük anahtar-değer deposu boyutu - Uygulamalar toplamda yalnızca 64 kilobayt kadar anahtar-değer verisi depolayabilir. Bu sınırı aşan anahtarları ayarlama denemeleri başarısız olur ve önceki değer kalıcı olur.

  • Veri türleri - Yalnızca dizeler, sayılar ve boole'lar gibi temel türler depolanabilir.

iCloudKeyValue örneği nasıl çalıştığını gösterir. Örnek kod, her cihaz için adlı bir anahtar oluşturur: Bu anahtarı bir cihazda ayarlayabilir ve değerin başkalarına yayılmasını izleyebilirsiniz. Ayrıca, herhangi bir cihazda düzenlenebilen "Paylaşılan" adlı bir anahtar da oluşturur - aynı anda birçok cihazda düzenleme yaparsanız, iCloud hangi değerin "kazanacağını" (değişiklikte bir zaman damgası kullanarak) karar verir ve yayılır.

Bu ekran görüntüsü kullanımdaki örneği gösterir. iCloud'dan değişiklik bildirimleri alındığında, bunlar ekranın en altındaki kaydırma metin görünümünde yazdırılır ve giriş alanlarında güncelleştirilir.

Cihazlar arasındaki ileti akışı

Verileri ayarlama ve alma

Bu kod, bir dize değerinin nasıl ayarlandığını gösterir.

var store = NSUbiquitousKeyValueStore.DefaultStore;
store.SetString("testkey", "VALUE IN THE CLOUD");  // key and value
store.Synchronize();

Eşitleme çağrısı değerin yalnızca yerel disk depolamada kalıcı olmasını sağlar. iCloud'a eşitleme arka planda gerçekleşir ve uygulama kodu tarafından "zorlanamaz". İyi ağ bağlantısı ile eşitleme genellikle 5 saniye içinde gerçekleşir, ancak ağ zayıfsa (veya bağlantısı kesilirse) bir güncelleştirme çok daha uzun sürebilir.

Bu kodla bir değer alabilirsiniz:

var store = NSUbiquitousKeyValueStore.DefaultStore;
display.Text = store.GetString("testkey");

Değer yerel veri deposundan alınır - bu yöntem "en son" değeri almak için iCloud sunucularına başvurmaya çalışmaz. iCloud, yerel veri deposunu kendi zamanlamasına göre güncelleştirir.

Veri silme

Anahtar-değer çiftini tamamen kaldırmak için Aşağıdaki gibi Remove yöntemini kullanın:

var store = NSUbiquitousKeyValueStore.DefaultStore;
store.Remove("testkey");
store.Synchronize();

Değişiklikleri Gözlemleme

Bir uygulama, değerleri iCloud tarafından değiştirildiğinde de öğesine bir gözlemci NSNotificationCenter.DefaultCenterekleyerek bildirim alabilir. KeyValueViewController.csViewWillAppear yönteminden alınan aşağıdaki kod, bu bildirimleri dinlemeyi ve hangi anahtarların değiştirildiğinin listesini oluşturmayı gösterir:

keyValueNotification =
NSNotificationCenter.DefaultCenter.AddObserver (
    NSUbiquitousKeyValueStore.DidChangeExternallyNotification, notification => {
    Console.WriteLine ("Cloud notification received");
    NSDictionary userInfo = notification.UserInfo;

    var reasonNumber = (NSNumber)userInfo.ObjectForKey (NSUbiquitousKeyValueStore.ChangeReasonKey);
    nint reason = reasonNumber.NIntValue;

    var changedKeys = (NSArray)userInfo.ObjectForKey (NSUbiquitousKeyValueStore.ChangedKeysKey);
    var changedKeysList = new List<string> ();
    for (uint i = 0; i < changedKeys.Count; i++) {
        var key = changedKeys.GetItem<NSString> (i); // resolve key to a string
        changedKeysList.Add (key);
    }
    // now do something with the list...
});

Kodunuz daha sonra değiştirilen anahtarların listesiyle ilgili olarak yerel bir kopyasını güncelleştirme veya kullanıcı arabirimini yeni değerlerle güncelleştirme gibi bazı eylemler gerçekleştirebilir.

Olası değişiklik nedenleri şunlardır: ServerChange (0), InitialSyncChange (1) veya QuotaViolationChange (2). Nedene erişebilir ve gerekirse farklı işlemler gerçekleştirebilirsiniz (örneğin, QuotaViolationChange sonucunda bazı anahtarları kaldırmanız gerekebilir).

Belge Depolama

iCloud Document Depolama, uygulamanız (ve kullanıcı için) için önemli olan verileri yönetmek için tasarlanmıştır. Uygulamanızın çalıştırması gereken dosyaları ve diğer verileri yönetmek için kullanılırken, aynı zamanda kullanıcının tüm cihazlarında iCloud tabanlı yedekleme ve paylaşım işlevselliği sağlar.

Bu diyagramda, bunların birbirine nasıl uyduğu gösterilmektedir. Her cihazda yerel depolama alanına kaydedilmiş veriler vardır (UbiquityContainer) ve işletim sisteminin iCloud Daemon'ı bulutta veri gönderme ve alma işlemini üstlenir. Eşzamanlı erişimi önlemek için UbiquityContainer'a tüm dosya erişimi FilePresenter/FileCoordinator aracılığıyla yapılmalıdır. sınıfı UIDocument bunları sizin için uygular; bu örnekte UIDocument'ın nasıl kullanılacağı gösterilmektedir.

Belge depolamaya genel bakış

iCloudUIDoc örneği, tek bir metin alanı içeren basit UIDocument bir alt sınıf uygular. Metin bir UITextView içinde işlenir ve düzenlemeler iCloud tarafından kırmızı renkte gösterilen bir bildirim iletisiyle diğer cihazlara yayılır. Örnek kod, çakışma çözümü gibi daha gelişmiş iCloud özellikleriyle ilgilenmez.

Bu ekran görüntüsünde örnek uygulama gösterilmektedir. Metni değiştirdikten ve UpdateChangeCount tuşuna bastıktan sonra belge iCloud aracılığıyla diğer cihazlarla eşitlenir.

Bu ekran görüntüsü, metni değiştirdikten ve UpdateChangeCount tuşuna bastıktan sonra örnek uygulamayı gösterir

iCloudUIDoc örneğinin beş bölümü vardır:

  1. UbiquityContainer'a erişme - iCloud'un etkinleştirilip etkinleştirilmediğini ve etkinleştirilip etkinleştirilmediğini uygulamanızın iCloud depolama alanına giden yolu belirleyin.

  2. UIDocument alt sınıfı oluşturma - iCloud depolama alanı ile model nesneleriniz arasında ara sınıf oluşturma.

  3. iCloud belgelerini bulma ve açma - NSFileManagerNSPredicate iCloud belgelerini bulmak ve açmak için ve kullanın.

  4. iCloud belgelerini görüntüleme - kullanıcı arabirimi denetimleriyle etkileşim kurabilmeniz için özelliklerinizi UIDocument kullanıma sunar.

  5. iCloud belgelerini kaydetme - Kullanıcı arabiriminde yapılan değişikliklerin diskte ve iCloud'da kalıcı olduğundan emin olun.

Bir şeyin gerçekleşmesini beklerken engellememeleri için tüm iCloud işlemleri zaman uyumsuz olarak çalıştırılır (veya çalıştırılmalıdır). Örnekte bunu yapmanın üç farklı yolunu göreceksiniz:

İş parçacıkları - AppDelegate.FinishedLaunching için ilk çağrıdaGetUrlForUbiquityContainer, ana iş parçacığının engellenmesini önlemek için başka bir iş parçacığında yapılır.

NotificationCenter - tamamlandı gibi NSMetadataQuery.StartQuery zaman uyumsuz işlemler tamamlandığında bildirimlere kaydolma.

Tamamlama İşleyicileri - gibi UIDocument.Openzaman uyumsuz işlemleri tamamlarken çalıştırılacak yöntemleri geçirme.

UbiquityContainer'a erişme

iCloud Belgesi Depolama kullanmanın ilk adımı, iCloud'un etkinleştirilip etkinleştirilmediğini ve etkinse "yaygınlık kapsayıcısının" konumunu (iCloud özellikli dosyaların cihazda depolandığı dizin) belirlemektir.

Bu kod, örneğin yöntemindedir AppDelegate.FinishedLaunching .

// GetUrlForUbiquityContainer is blocking, Apple recommends background thread or your UI will freeze
ThreadPool.QueueUserWorkItem (_ => {
    CheckingForiCloud = true;
    Console.WriteLine ("Checking for iCloud");
    var uburl = NSFileManager.DefaultManager.GetUrlForUbiquityContainer (null);
    // OR instead of null you can specify "TEAMID.com.your-company.ApplicationName"

    if (uburl == null) {
        HasiCloud = false;
        Console.WriteLine ("Can't find iCloud container, check your provisioning profile and entitlements");

        InvokeOnMainThread (() => {
            var alertController = UIAlertController.Create ("No \uE049 available",
            "Check your Entitlements.plist, BundleId, TeamId and Provisioning Profile!", UIAlertControllerStyle.Alert);
            alertController.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Destructive, null));
            viewController.PresentViewController (alertController, false, null);
        });
    } else { // iCloud enabled, store the NSURL for later use
        HasiCloud = true;
        iCloudUrl = uburl;
        Console.WriteLine ("yyy Yes iCloud! {0}", uburl.AbsoluteUrl);
    }
    CheckingForiCloud = false;
});

Örnek bunu yapmasa da Apple, bir uygulama ön plana geldiğinde GetUrlForUbiquityContainer'ı çağırmanızı önerir.

UIDocument Alt Sınıfı Oluşturma

Tüm iCloud dosyaları ve dizinleri (yani UbiquityContainer dizininde depolanan her şey) NSFileManager yöntemleri kullanılarak yönetilmeli, NSFilePresenter protokolü uygulanmalıdır ve bir NSFileCoordinator aracılığıyla yazılmalıdır. Bunların tümünü yapmanın en basit yolu, kendiniz yazmak değil, her şeyi sizin için yapan UIDocument alt sınıfıdır.

iCloud ile çalışmak için UIDocument alt sınıfında uygulamanız gereken yalnızca iki yöntem vardır:

  • LoadFromContents - Model sınıfınıza/es'inize paketi açmanız için dosyanın içeriğinin NSData'sını geçirir.

  • ContentsForType - Diske (ve Buluta) kaydedilecek model sınıfınızın/es'inizin NSData gösterimini sağlamanızı isteyin.

iCloudUIDoc\MonkeyDocument.cs'dan alınan bu örnek kod, UIDocument'ın nasıl uygulandığını gösterir.

public class MonkeyDocument : UIDocument
{
    // the 'model', just a chunk of text in this case; must easily convert to NSData
    NSString dataModel;
    // model is wrapped in a nice .NET-friendly property
    public string DocumentString {
        get {
            return dataModel.ToString ();
        }
        set {
            dataModel = new NSString (value);
        }
    }
    public MonkeyDocument (NSUrl url) : base (url)
    {
        DocumentString = "(default text)";
    }
    // contents supplied by iCloud to display, update local model and display (via notification)
    public override bool LoadFromContents (NSObject contents, string typeName, out NSError outError)
    {
        outError = null;

        Console.WriteLine ("LoadFromContents({0})", typeName);

        if (contents != null)
            dataModel = NSString.FromData ((NSData)contents, NSStringEncoding.UTF8);

        // LoadFromContents called when an update occurs
        NSNotificationCenter.DefaultCenter.PostNotificationName ("monkeyDocumentModified", this);
        return true;
    }
    // return contents for iCloud to save (from the local model)
    public override NSObject ContentsForType (string typeName, out NSError outError)
    {
        outError = null;

        Console.WriteLine ("ContentsForType({0})", typeName);
        Console.WriteLine ("DocumentText:{0}",dataModel);

        NSData docData = dataModel.Encode (NSStringEncoding.UTF8);
        return docData;
    }
}

Bu örnekteki veri modeli çok basittir- tek bir metin alanı. Veri modeliniz, xml belgesi veya ikili veri gibi gerektiği kadar karmaşık olabilir. UIDocument uygulamasının birincil rolü, model sınıflarınız ile diske kaydedilebilen/yüklenebilen bir NSData gösterimi arasında çeviri yapmaktır.

iCloud Belgelerini Bulma ve Açma

Örnek uygulama yalnızca tek bir dosyayla (test.txt) ilgilenir, bu nedenle AppDelegate.cs içindeki kod özel olarak bu dosya adını aramak için bir NSPredicate ve NSMetadataQuery oluşturur. zaman NSMetadataQuery uyumsuz olarak çalışır ve tamamlandığında bir bildirim gönderir. DidFinishGatheringbildirim gözlemcisi tarafından çağrılır, sorguyu durdurur ve dosyayı yükleyip içinde MonkeyDocumentViewControllergörüntülemeye çalışmak için tamamlama işleyicisi ile yöntemini kullanan UIDocument.Open LoadDocument'ı çağırır.

string monkeyDocFilename = "test.txt";
void FindDocument ()
{
    Console.WriteLine ("FindDocument");
    query = new NSMetadataQuery {
        SearchScopes = new NSObject [] { NSMetadataQuery.UbiquitousDocumentsScope }
    };

    var pred = NSPredicate.FromFormat ("%K == %@", new NSObject[] {
        NSMetadataQuery.ItemFSNameKey, new NSString (MonkeyDocFilename)
    });

    Console.WriteLine ("Predicate:{0}", pred.PredicateFormat);
    query.Predicate = pred;

    NSNotificationCenter.DefaultCenter.AddObserver (
        this,
        new Selector ("queryDidFinishGathering:"),
        NSMetadataQuery.DidFinishGatheringNotification,
        query
    );

    query.StartQuery ();
}

[Export ("queryDidFinishGathering:")]
void DidFinishGathering (NSNotification notification)
{
    Console.WriteLine ("DidFinishGathering");
    var metadataQuery = (NSMetadataQuery)notification.Object;
    metadataQuery.DisableUpdates ();
    metadataQuery.StopQuery ();

    NSNotificationCenter.DefaultCenter.RemoveObserver (this, NSMetadataQuery.DidFinishGatheringNotification, metadataQuery);
    LoadDocument (metadataQuery);
}

void LoadDocument (NSMetadataQuery metadataQuery)
{
    Console.WriteLine ("LoadDocument");

    if (metadataQuery.ResultCount == 1) {
        var item = (NSMetadataItem)metadataQuery.ResultAtIndex (0);
        var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);
        doc = new MonkeyDocument (url);

        doc.Open (success => {
            if (success) {
                Console.WriteLine ("iCloud document opened");
                Console.WriteLine (" -- {0}", doc.DocumentString);
                viewController.DisplayDocument (doc);
            } else {
                Console.WriteLine ("failed to open iCloud document");
            }
        });
    } // TODO: if no document, we need to create one
}

iCloud Belgelerini Görüntüleme

UIDocument'ın görüntülenmesi başka bir model sınıfından farklı olmamalıdır. Özellikler kullanıcı tarafından düzenlenmiş ve sonra modele geri yazılan kullanıcı arabirimi denetimlerinde görüntülenir.

Örnekte iCloudUIDoc\MonkeyDocumentViewController.cs içinde MonkeyDocument metnini UITextViewgörüntüler. ViewDidLoad yönteminde MonkeyDocument.LoadFromContents gönderilen bildirimi dinler. LoadFromContents iCloud dosya için yeni veriye sahip olduğunda çağrılır, böylece bildirim belgenin güncelleştirildiğini gösterir.

NSNotificationCenter.DefaultCenter.AddObserver (this,
    new Selector ("dataReloaded:"),
    new NSString ("monkeyDocumentModified"),
    null
);

Örnek kod bildirim işleyicisi, herhangi bir çakışma algılama veya çözüm olmadan kullanıcı arabirimini güncelleştirmek için bir yöntem çağırır.

[Export ("dataReloaded:")]
void DataReloaded (NSNotification notification)
{
    doc = (MonkeyDocument)notification.Object;
    // we just overwrite whatever was being typed, no conflict resolution for now
    docText.Text = doc.DocumentString;
}

iCloud Belgelerini Kaydetme

iCloud'a UIDocument eklemek için doğrudan arayabilir UIDocument.Save (yalnızca yeni belgeler için) veya kullanarak mevcut bir dosyayı taşıyabilirsiniz NSFileManager.DefaultManager.SetUbiquitious. Örnek kod, bu kodla doğrudan yaygınlık kapsayıcısında yeni bir belge oluşturur (burada biri işlem için, diğeri Open için Save olmak üzere iki tamamlama işleyicisi vardır):

var docsFolder = Path.Combine (iCloudUrl.Path, "Documents"); // NOTE: Documents folder is user-accessible in Settings
var docPath = Path.Combine (docsFolder, MonkeyDocFilename);
var ubiq = new NSUrl (docPath, false);
var monkeyDoc = new MonkeyDocument (ubiq);
monkeyDoc.Save (monkeyDoc.FileUrl, UIDocumentSaveOperation.ForCreating, saveSuccess => {
Console.WriteLine ("Save completion:" + saveSuccess);
if (saveSuccess) {
    monkeyDoc.Open (openSuccess => {
        Console.WriteLine ("Open completion:" + openSuccess);
        if (openSuccess) {
            Console.WriteLine ("new document for iCloud");
            Console.WriteLine (" == " + monkeyDoc.DocumentString);
            viewController.DisplayDocument (monkeyDoc);
        } else {
            Console.WriteLine ("couldn't open");
        }
    });
} else {
    Console.WriteLine ("couldn't save");
}

Belgedeki sonraki değişiklikler doğrudan "kaydedilmez", bunun yerine ile UpdateChangeCountdeğiştirildiğini söyleriz UIDocument ve otomatik olarak diske kaydetme işlemi zamanlar:

doc.UpdateChangeCount (UIDocumentChangeKind.Done);

iCloud Belgelerini Yönetme

Kullanıcılar, Ayarlar aracılığıyla uygulamanızın dışındaki "ubiquity kapsayıcısının" Documents dizinindeki iCloud belgelerini yönetebilir; dosya listesini görüntüleyebilir ve silmek için çekin. Uygulama kodu, belgelerin kullanıcı tarafından silindiği durumu işleyebilmelidir. İç uygulama verilerini Belgeler dizininde depolamayın.

iCloud Belgeleri iş akışını yönetme

Kullanıcılar ayrıca, iCloud özellikli bir uygulamayı cihazlarından kaldırmaya çalıştıklarında, bu uygulamayla ilgili iCloud belgelerinin durumunu bildirmek için farklı uyarılar alır.

Belge Güncelleştirmeler Beklemede için bir uyarıyı gösteren ekran görüntüsü.

i Bulutu Sil için bir uyarıyı gösteren ekran görüntüsü.

iCloud Backup

iCloud'a yedekleme, geliştiriciler tarafından doğrudan erişilen bir özellik olmasa da, uygulamanızı tasarlama şekliniz kullanıcı deneyimini etkileyebilir. Apple, geliştiricilerin iOS uygulamalarında izlemesi için iOS Veri Depolama Yönergeleri sağlar.

En önemli nokta, uygulamanızın kullanıcı tarafından oluşturulmayan büyük dosyaları depolayıp depolamadığıdır (örneğin, sorun başına yüz artı megabayt içerik depolayan bir dergi okuyucu uygulaması). Apple, bu tür verileri iCloud'a yedeklenecek ve kullanıcının iCloud kotasını gereksiz yere dolduracak şekilde depolamamanızı tercih eder.

Bunun gibi büyük miktarda veri depolayan uygulamalar, bu verileri yedeklenmemiş kullanıcı dizinlerinden birinde depolamalıdır (örn. önbellekler veya tmp) veya iCloud'un yedekleme işlemleri sırasında bunları yoksayması için bu dosyalara bayrak uygulamak için kullanın NSFileManager.SetSkipBackupAttribute .

Özet

Bu makalede, iOS 5'te yer alan yeni iCloud özelliği tanıtıldı. Projenizi iCloud kullanacak şekilde yapılandırmak için gereken adımları inceledi ve ardından iCloud özelliklerinin nasıl uygulandığına ilişkin örnekler sağladı.

Anahtar-değer depolama örneği, ICloud'un NSUserPreferences'ın depolandığı gibi az miktarda veriyi depolamak için nasıl kullanılabileceğini göstermiştir. UIDocument örneği, iCloud aracılığıyla birden çok cihazda ne kadar karmaşık verilerin depolanabileceğini ve eşitlenebileceğini gösterdi.

Son olarak, iCloud Backup'ın eklenmesinin uygulama tasarımınızı nasıl etkilediği hakkında kısa bir tartışma içeriyor.