Mantenere sincronizzati i dati delle applicazioni tra i dispositivi è un compito complesso e scoraggiante. Fortunatamente, questo è esattamente il motivo per cui Apple ha creato iCloud. In questa serie di Tuts + Premium, imparerai come funziona iCloud e come le tue applicazioni possono condividere i dati in modo trasparente su più dispositivi.
Nella seconda parte di questa serie, ti ho mostrato come sfruttare lo Storage a valore chiave di iCloud per mantenere sincronizzate piccole quantità di dati utente su più dispositivi. Anche se il Key-Value Storage è facile da usare e adottare, uno dei lati negativi è la limitazione che pone sulla quantità di dati che possono essere memorizzati. Ricorda che ogni applicazione può archiviare solo 1 MB di dati e il numero di coppie chiave-valore è limitato a 1024. Come accennato alla fine del tutorial precedente, il nostro gestore di segnalibri potrebbe incorrere in questa limitazione se qualcuno dei nostri utenti desidera archiviare un sacco di segnalibri.
La soluzione a questo problema è il passaggio da iCloud Key-Value Storage a iCloud Document Storage per la memorizzazione dei segnalibri. In termini di spazio su disco, iCloud Document Storage è limitato solo dalla memoria iCloud dell'utente. Sapendo che un account gratuito viene fornito con 5 GB di archiviazione dei dati, iCloud Document Storage è la soluzione ideale per il nostro gestore di segnalibri. In questo tutorial, noi refactoring il gestore dei segnalibri dall'utilizzo di iCaloud Key-Value Storage all'adozione di iCloud Document Storage.
Vorrei sottolineare che è importante aver letto la prima e la seconda puntata di questa serie prima di leggere questo pezzo. In questo tutorial, ci sarà il refactoring del nostro gestore di segnalibri basandoci sulle fondamenta che abbiamo depositato nella parte 2 della serie.
UIDocument
Con l'introduzione di iCloud, anche Apple ha realizzato UIDocument
disponibile per gli sviluppatori. Gli ingegneri di Apple hanno creato UIDocument
con iCloud in mente. UIDocument
l'integrazione di iCloud per l'applicazione basata su documenti è molto più semplice. Tuttavia, è importante notare che UIDocument
fa molto di più che fornire un'API facile da usare per l'integrazione con iCloud.
Le applicazioni basate su documenti devono affrontare una serie di sfide, come (1) leggere e scrivere dati da e su disco senza bloccare l'interfaccia utente, (2) salvare i dati su disco a intervalli appropriati e (3) integrare opzionalmente con iCloud. UIDocument
fornisce soluzioni integrate per queste sfide.
Prima di iniziare a lavorare con UIDocument
, Voglio chiarire cosa UIDocument
è e cosa non lo è. UIDocument
è un oggetto controller che gestisce uno o più modelli proprio come UIViewController
controlla e gestisce una o più viste. UIDocument
non memorizza alcun dato, ma gestisce gli oggetti del modello che contengono i dati dell'utente. Questo è un concetto importante da comprendere, che diventerà più chiaro quando inizieremo a ridefinire la nostra applicazione UIDocument
.
Un altro concetto importante da capire è come funzionano le operazioni di lettura e scrittura durante l'uso UIDocument
. Se decidi di usare UIDocument
nella propria applicazione, non è necessario preoccuparsi di bloccare il thread principale durante la lettura o la scrittura di dati su disco. Quando si usa UIDocument
, il sistema operativo gestirà automaticamente un numero di attività per te su una coda in background e assicurerà che il thread principale rimanga reattivo. Mi piacerebbe prendere un momento e spiegare ogni operazione in modo più dettagliato per darvi una buona comprensione delle diverse parti mobili coinvolte.
Iniziamo con la lettura dei dati dal disco. L'operazione di lettura inizia con un'operazione aperta avviata sulla coda chiamante. L'operazione di apertura viene avviata quando viene aperto un documento inviandogli un messaggio di openWithCompletionHandler:. Passiamo un gestore di completamento che viene richiamato quando l'intera operazione di lettura è terminata. Questo è un aspetto importante delle operazioni di lettura e scrittura. Può richiedere una quantità non trascurabile di tempo per leggere o scrivere i dati da o su disco, e non vogliamo farlo sul thread principale e bloccare l'interfaccia utente. L'operazione di lettura effettiva si svolge in una coda in background gestita dal sistema operativo. Al termine dell'operazione di lettura, il file loadFromContents: OfType: errore: il metodo è chiamato sul documento. Questo metodo invia UIDocument
i dati necessari per inizializzare il (i) modello (i) che gestisce. Il gestore di completamento viene richiamato al termine di questo processo, il che significa che possiamo rispondere al caricamento del documento, ad esempio aggiornando l'interfaccia utente con il contenuto del documento.
L'operazione di scrittura è simile. Inizia con un'operazione di salvataggio avviata nella coda chiamante inviando saveToURL: forSaveOperation: completionHandler: all'oggetto del documento. Come con l'operazione di lettura, passiamo un gestore di completamento che viene richiamato al termine dell'operazione di scrittura. La scrittura dei dati sul disco avviene in una coda di sfondo. Il sistema operativo chiede UIDocument
per un'istantanea dei dati del modello inviandogli un messaggio di contentsForType: errore:. Il gestore di completamento viene richiamato al termine dell'operazione di scrittura, che ci dà l'opportunità di aggiornare l'interfaccia utente.
UIDocument
è una classe base e non è pensata per essere utilizzata direttamente. Abbiamo bisogno di sottoclasse UIDocument
e adattarlo alle nostre esigenze. In altre parole, abbiamo sottoclasse UIDocument
in modo che conosca il nostro modello e come gestirlo. Nella sua forma più semplice, la sottoclasse UIDocument
ci richiede solo di scavalcare loadFromContents: OfType: errore: per leggere e contentsForType: errore: per scrivere.
Confuso? Tu dovresti essere. Nonostante UIDocument
rende la vita molto più facile, è una classe avanzata e abbiamo a che fare con un argomento complesso. Tuttavia, sono convinto che riuscirai a capire bene le applicazioni basate su documenti una volta che abbiamo refactorato la nostra applicazione.
Prima di continuare, voglio chiarire quali sono i nostri obiettivi per questo tutorial. L'obiettivo principale è quello di ridefinire la nostra applicazione per utilizzare iCloud Document Storage invece di iCloud Key-Value Storage. Ciò significa che faremo uso di UIDocument
e sottoclassi per soddisfare i nostri bisogni. Inoltre, creeremo una classe modello personalizzata per il nostro segnalibro che verrà utilizzato e gestito da UIDocument
sottoclasse.
Al momento, la nostra applicazione è configurata per utilizzare solo lo Storage valore-chiave. Per abilitare Document Storage, dobbiamo prima configurare le autorizzazioni della nostra applicazione. Apri il Target Editor selezionando la nostra applicazione nel Project Navigator e seleziona l'unico bersaglio dalla lista dei bersagli. Nel I diritti sezione, dovresti vedere Contenitori iCloud sotto iCaloud Key-Value Store. La lista accanto a Contenitori iCloud è vuoto al momento Fai clic sul pulsante più nella parte inferiore dell'elenco e vedrai che Xcode crea un identificatore del contenitore iCloud per te che corrisponde all'identificativo del bundle della tua appicazione.
Cos'è un contenitore iCloud? Come suggerisce il nome, è un contenitore nell'archivio dati iCloud dell'utente. Specificando uno (o più) contenitori iCloud nel file delle autorizzazioni della nostra applicazione, comunichiamo al sistema operativo a quali contenitori ha accesso la nostra applicazione.
Nel precedente tutorial, abbiamo memorizzato ogni segnalibro come istanza di NSDictionary
, ma questa non è una buona soluzione per un'applicazione basata su documenti. Invece, creeremo una classe di segnalibri personalizzata che ci consentirà di archiviare facilmente i suoi dati.
Crea un nuovo NSObject
sottoclasse scegliendo File dal menu, selezionando Nuovo, e poi File… . Selezionare Cocoa Touch dal pannello di sinistra e scegliere Classe Objective-C dall'elenco di modelli sulla destra. Dai un nome alla classe Segnalibro e assicurarsi che sia una sottoclasse di NSObject. Specificare dove si desidera salvare la nuova classe e colpire Creare.
Nel file di intestazione del nostro modello, aggiungiamo le due proprietà del modello di segnalibro che abbiamo usato nel tutorial precedente, a nome e a URL. Entrambe le proprietà sono istanze di NSString
. Dichiariamo anche un inizializzatore designato, che prende un nome e un URL come parametri. Infine, è importante garantire che il nostro Segnalibro
classe conforme al NSCoding
protocollo.
#importare@interface Segnalibro: NSObject NSString * _name; NSString * _url; @property (nonatomic, copy) NSString * nome; @property (nonatomic, copy) NSString * url; - (id) initWithName: (NSString *) nome eURL: (NSString *) url; @fine
Nel file di implementazione del nostro modello, per prima cosa definiamo due costanti per il nome e l'URL del nostro segnalibro. Questa è una buona pratica in quanto ridurrà al minimo la possibilità di digitare in modo errato le chiavi che verranno utilizzate a breve. Successivamente, implementiamo il nostro metodo di inizializzazione. Questo metodo è semplice. Inizializziamo la nostra istanza e assegniamo il nome e l'URL alle nostre variabili di istanza del segnalibro.
La parte importante è implementare i metodi richiesti per rendere il Segnalibro
classe conforme al NSCoding
protocollo. Se la NSCoding
il protocollo è nuovo per te, quindi ti invito a leggere la Guida alla Programmazione di Archivi e Serializzazioni in quanto questo è un argomento importante per qualsiasi sviluppatore Cocoa-Touch. L'essenza di ciò è che il NSCoding
il protocollo ci consente di archiviare e disarchiviare facilmente le istanze di Segnalibro
classe.
#import "Bookmark.h" #define kBookmarkName @ "Nome segnalibro" #define kBookmarkURL @ "Bookmark URL" @implementation Segnalibro @synthesize nome = _name, url = _url; #pragma mark - #pragma mark Initialization - (id) initWithName: (NSString *) name andURL: (NSString *) url self = [super init]; if (self) self.name = name; self.url = url; return self; #pragma mark - #pragma mark NSCoding Protocol - (void) encodeWithCoder: (NSCoder *) coder [coder encodeObject: self.name forKey: kBookmarkName]; [coder encodeObject: self.url forKey: kBookmarkURL]; - (id) initWithCoder: (NSCoder *) coder self = [super init]; if (self! = nil) self.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [coder decodeObjectForKey: kBookmarkURL]; return self; @fine
subclassing UIDocument
non è così difficile come potresti pensare. Come ho detto prima, tutto ciò che dobbiamo fare è sovrascrivere due metodi e creare una proprietà per il modello di segnalibro che gestirà.
Crea una nuova classe proprio come abbiamo fatto per la nostra Segnalibro
classe e dargli un nome BookmarkDocument
. Assicurati che sia una sottoclasse di UIDocument
. Nel file di intestazione del nostro UIDocument
sottoclasse, aggiungiamo una dichiarazione in avanti per il Segnalibro
classe e creiamo una proprietà per il nostro modello di segnalibro. Non dimenticare di sintetizzare gli accessor per questa proprietà.
#importare@class Bookmark; @interface BookmarkDocument: UIDocument Bookmark * _bookmark; @property (nonatomic, strong) Segnalibro * segnalibro; @fine
Nel file di implementazione importiamo il file di intestazione del file Segnalibro classificare e definire un'altra costante da utilizzare come chiave per archiviare e annullare l'archiviazione del modello di segnalibro. Come ho detto prima, abbiamo solo bisogno di sovrascrivere due metodi nel UIDocument sottoclasse, (1) loadFromContents: OfType: errore: e (2) contentsForType: errore:. Il primo metodo verrà invocato quando apriamo un documento, mentre il secondo metodo verrà invocato quando viene salvato un documento. Entrambi i metodi sono chiamati dal sistema operativo. Non abbiamo mai bisogno di chiamare questi mehod direttamente.
#import "BookmarkDocument.h" #import "Bookmark.h" #define kArchiveKey @ "Bookmark" @implementation BookmarkDocument @synthesize bookmark = _bookmark;
Lascia che ti guidi loadFromContents: OfType: errore:. Il primo argomento è contenuto di tipo id
. Questo può essere un esempio di NSData
o NSFileWrapper
. Quest'ultimo è applicabile solo quando l'applicazione utilizza pacchetti di file. Nel nostro caso, possiamo aspettarci un NSData
esempio. Per prima cosa controlliamo se la lunghezza del NSData
l'istanza non è uguale a zero. Inizializziamo un'istanza di NSKeyedUnarchiver
e fornirlo con il contenuto oggetto. Decodificando i dati, otteniamo un'istanza di Segnalibro
classe indietro. Questo è il motivo per cui il Segnalibro
classe conforme al NSCoding
protocollo. Se la lunghezza del NSData
l'istanza è uguale a zero, inizializziamo un nuovo segnalibro con valori predefiniti per nome e URL. Nota che torniamo SÌ
alla fine del metodo.
- (BOOL) loadFromContents: (id) contents ofType: (NSString *) typeName error: (NSError * __ autoreleasing *) outError if ([lunghezza contenuto]> 0) NSKeyedUnarchiver * unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: contenuto]; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [unarchiver finishDecoding]; else self.bookmark = [[Assegnazione segnalibri] initWithName: @ "Nome segnalibro" eURL: @ "www.esempio.com"]; return YES;
Il contentsForType: errore: il metodo fa il contrario. Cioè, forniamo i dati che devono essere scritti sul disco. Questo oggetto dati è la cosiddetta istantanea dei dati del nostro modello. Lo facciamo inizializzando un'istanza di NSMutableData
e usalo per inizializzare un'istanza di NSKeyedArchiver
. Possiamo quindi archiviare la nostra istanza del segnalibro in modo che possa essere scritta su disco. Questo metodo si aspetta che restituiamo un'istanza di NSData
e questo è esattamente ciò che facciamo. Nostro UIDocument
la sottoclasse ora è pronta per noi da usare.
- (id) contentsForType: (NSString *) typeName error: (NSError * __ autoreleasing *) outError NSMutableData * data = [[NSMutableData alloc] init]; NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data]; [archiver encodeObject: self.bookmark forKey: kArchiveKey]; [archiver finishEncoding]; restituire i dati;
Ci sono quattro elementi della nostra applicazione che devono essere refactored se vogliamo utilizzare iCloud Document Storage:
(1) caricamento, (2) visualizzazione, (3) salvataggio e (4) cancellazione di segnalibri. Iniziamo con il caricamento dei segnalibri.
Prima di dare un'occhiata al loadBookmarks metodo, abbiamo bisogno di dichiarare una proprietà privata, un'istanza di NSMetadataQuery
. Diventerà chiaro il motivo per cui dobbiamo farlo in pochi minuti. Non dimenticare di aggiungere due istruzioni di importazione extra al file di implementazione del nostro controller di visualizzazione, uno per il Segnalibro
classe e uno per il BookmarkDocument
classe.
#import "ViewController.h" #import "Bookmark.h" #import "BookmarkDocument.h" #import "AddBookmarkViewController.h" @interface ViewController () NSMetadataQuery * _query; @property (nonatomic, strong) NSMetadataQuery * query; @end @implementation ViewController @synthesize bookmarks = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;
Invece di NSDictionary
istanze, la nostra matrice di segnalibri, l'origine dati della nostra vista tabella conterrà istanze di BookmarkDocument
classe. Diamo un'occhiata al refactored loadBookmarks metodo. Iniziamo inizializzando l'array di segnalibri. Successivamente, chiediamo NSFileManager
per l'URL del contenitore iCloud che useremo per memorizzare i nostri segnalibri. Non lasciarti scappare dal nome colorato di questo metodo. URLForUbiquityContainerIdentifier: accetta un argomento, l'identificatore del contenitore iCloud a cui vogliamo accedere. Passando a zero come argomento, NSFileManager
selezionerà automaticamente il primo contenitore iCloud dichiarato nel file delle autorizzazioni della nostra applicazione. Si noti che se si specifica un identificatore del contenitore iCloud, è necessario fornire anche l'identificatore del team. Il formato corretto è
- (void) loadBookmarks if (! self.bookmarks) self.bookmarks = [[NSMutableArray alloc] init]; NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) self.query = [[NSMetadataQuery alloc] init]; [self.query setSearchScopes: [NSArray arrayWithObject: NSMetadataQueryUbiquitousDocumentsScope]]; NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "% K like '*'", NSMetadataItemFSNameKey]; [self.query setPredicate: predicate]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; [nc addObserver: self-selector: @selector (queryDidFinish :) nome: NSMetadataQueryDidFinishGatheringNotification object: self.query]; [nc addObserver: self-selector: @selector (queryDidUpdate :) nome: NSMetadataQueryDidUpdateNotification oggetto: self.query]; [self.query startQuery];
Questo metodo non è solo per scoprire dove possiamo archiviare i nostri documenti iCloud. Chiamando con successo questo metodo, il sistema operativo estenderà la sandbox dell'applicazione per includere la directory del contenitore iCloud che abbiamo specificato. Ciò significa che dobbiamo chiamare questo metodo prima di poter iniziare a leggere o scrivere dati su questa directory. Se dovessi registrare l'URL restituito alla console, noterai due stranezze, (1) l'URL restituito per il contenitore iCloud è un URL locale (situato sul dispositivo stesso), e (2) questo URL locale non è attivo nella sandbox della nostra applicazione. Il modo in cui iCloud funziona è che archiviamo i documenti che vogliamo archiviare in iCloud in questa directory locale NSFileManager
ci fornisce Il demone iCloud, in esecuzione sul nostro dispositivo in background, si prenderà cura dell'aspetto di sincronizzazione dei documenti e lo farà anche se la nostra applicazione non è in esecuzione.
Poiché l'URL locale vive al di fuori della sandbox dell'applicazione, è necessario richiamare questo metodo prima di leggere o scrivere in questa directory. Invocando questo metodo chiediamo al sistema operativo il permesso di leggere e scrivere in questa directory.
Continuiamo a dissezionare il loadBookmarks metodo. Verifichiamo che l'URL da cui riusciamo NSFileManager
non è uguale a zero. Quest'ultimo implica due cose importanti, (1) abbiamo una posizione da cui possiamo leggere e scrivere e (2) iCloud è abilitato sul dispositivo. Il secondo punto è particolarmente importante in quanto non tutti i dispositivi avranno abilitato iCloud.
Se NSFileManager
ha effettivamente restituito un URL valido, inizializziamo un'istanza di NSMetadataQuery
e assegnarlo alla variabile di istanza che abbiamo dichiarato in precedenza. Il NSMetadataQuery
la classe ci consente di cercare nel contenitore iCloud i documenti. Dopo aver inizializzato un'istanza di NSMetadataQuery
, specifichiamo lo scopo della nostra ricerca. Nel nostro caso, cercheremo nel Documenti directory del nostro contenitore iCloud poiché quella è la posizione in cui archiviamo i documenti del segnalibro. È possibile perfezionare la query impostando un predicato di ricerca. Se hai familiarità con Core Data, allora questo non è nuovo per te. La nostra ricerca sarà semplice, cercheremo tutti i documenti nella directory dei documenti del nostro contenitore iCloud, quindi l'asterisco nel predicato.
Prima di iniziare la nostra query, è importante rendersi conto che non dovremmo aspettarci un risultato immediato dalla nostra query. Invece, registreremo il nostro controller di visualizzazione come un osservatore per il NSMetadataQueryDidUpdateNotification
e NSMetadataQueryDidFinishGatheringNotification
notifiche con la nostra istanza di query come mittente. Ciò significa che saremo avvisati quando la nostra query ha restituito risultati o quando i risultati sono stati aggiornati. Finalmente, iniziamo la query.
È importante mantenere un riferimento all'istanza della query per impedirne il rilascio. Questo è il motivo per cui il nostro controller di visualizzazione mantiene un riferimento alla query (come variabile di istanza) finché la query è in esecuzione.
Diamo un'occhiata al queryDidFinish: e queryDidUpdate: metodi di callback di notifica per vedere come gestire i risultati della query. Entrambi i metodi passano l'oggetto mittente della notifica, il NSMetadataQuery
esempio, per un metodo di convenienza, processQueryResults:. Quando diamo uno sguardo a questo metodo, vediamo che inizialmente iniziamo disattivando gli aggiornamenti per la query. Questo è importante in quanto i risultati della query possono ricevere aggiornamenti in tempo reale quando si verificano cambiamenti e dobbiamo prevenirli fino a quando stiamo elaborando i risultati della query. Successivamente, rimuoviamo tutti gli oggetti dalla nostra matrice di segnalibri ed enumeriamo i risultati della query. Ogni elemento nell'array dei risultati è un'istanza di NSMetadataItem
, che contiene i metadati associati a ciascun documento del segnalibro, incluso l'URL del file, necessario per aprire il documento. Chiediamo a ciascun elemento di metadati l'URL del file e inizializziamo il rispettivo documento.
Si noti che l'inizializzazione di un documento di segnalibri non significa che l'abbiamo caricata dal disco. Ricorda che questo è fatto inviando il nostro documento segnalibro un messaggio di openWithCompletionHandler:. Se l'operazione aperta ha esito positivo e il documento è caricato, lo aggiungiamo alla nostra serie di segnalibri e li visualizziamo nella vista tabella. Infine, dobbiamo rimuovere il nostro controller di visualizzazione come osservatore poiché non abbiamo più bisogno di ricevere notifiche a questo punto.
- (void) queryDidFinish: notifica (NSNotification *) NSMetadataQuery * query = [oggetto notifica]; // Stop Updates [query disableUpdates]; // Interrompi query [query stopQuery]; // Cancella segnalibri [self.bookmarks removeAllObjects]; [query.results enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * stop) NSURL * documentURL = [(NSMetadataItem *) obj valueForAttribute: NSMetadataItemURLKey]; BookmarkDocument * document = [[BookmarkDocument alloc] initWithFileURL: documentURL]; [document openWithCompletionHandler: ^ (BOOL successo) if (successo) [self.bookmarks addObject: document]; [self.tableView reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: self];
Il codice per visualizzare i segnalibri nella nostra vista tabella non ha bisogno di cambiare molto. Invece di recuperare il corretto NSDictionary
istanza dall'origine dati, recuperiamo un'istanza di BookmarkDocument
classe. Anche l'accesso al nome e all'URL del segnalibro deve essere aggiornato.
- (UITableViewCell *) tableView: (UITableView *) aTableView cellForRowAtIndexPath: (NSIndexPath *) indexPath static NSString * CellIdentifier = @ "Cell Identifier"; UITableViewCell * cell = [aTableView dequeueReusableCellWithIdentifier: CellIdentifier]; if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle riuseIdentifier: CellIdentifier]; // Recupera segnalibro BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row]; // Configura cella cell.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; cella di ritorno;
Dirigetevi verso il salvare: metodo in AddBookmarkViewController. Invece di creare un NSDictionary
e inviandolo al nostro controller di visualizzazione principale, ne creiamo uno nuovo Segnalibro
esempio. Questo è tutto. Il resto è gestito nel saveBookmark: metodo del nostro controller di visualizzazione principale. Non dimenticare di aggiungere una dichiarazione di importazione per Segnalibro
classe.
- (IBAction) salva: (id) mittente Segnalibro * segnalibro = [[Alloggiamento segnalibri] initWithName: self.nameField.text eURL: self.urlField.text]; [self.viewController saveBookmark: segnalibro]; [self dismissViewControllerAnimated: YES completion: nil];
Salvare un segnalibro nel nostro contenitore iCloud è quasi semplice come salvarlo nella sandbox dell'applicazione. Per prima cosa, chiediamo NSFileManager
per l'URL del nostro contenitore iCloud come abbiamo fatto in precedenza. Sulla base di tale URL, costruiamo l'URL corretto per il salvataggio del documento del segnalibro nel Documenti directory del contenitore iCloud. Il nome del nostro documento può essere qualunque cosa vogliamo che sia, purché il suo nome sia unico. Ho scelto di utilizzare il nome del segnalibro e un timestamp. L'utente non vedrà questo nome di file in modo che il nome non sia così importante. Ciò che è importante è che è unico.
Abbiamo un'istanza di un segnalibro, ma non abbiamo ancora un documento di segnalibro. Creiamo un nuovo documento di segnalibri inizializzandolo con l'URL appena creato. Successivamente, assegniamo il nostro nuovo segnalibro alla proprietà del segnalibro del documento. Infine, aggiungiamo il documento alla matrice dei segnalibri e ricarichiamo la vista tabella.
Salvare il documento nel contenitore iCloud è facile. Iniziamo l'operazione di salvataggio di cui ho parlato prima inviando il nostro nuovo documento al messaggio saveToURL: forSaveOperation: completionHandler:. Il secondo parametro di questo metodo specifica il tipo di operazione di salvataggio. Nel nostro caso, passiamo UIDocumentSaveForCreating
, il che significa creare un nuovo documento segnalibro. Dal momento che non abbiamo bisogno di fare nulla di speciale nel nostro esempio, semplicemente registriamo un messaggio alla console al termine dell'operazione di salvataggio.
Potresti aver notato che la nostra dichiarazione di metodo è leggermente cambiata. Non passiamo più un'istanza di NSDictionary
come l'unico argomento. Invece passiamo un'istanza del Segnalibro
classe. Assicurati di aggiornare il file di intestazione per riflettere questa modifica. Sarà inoltre necessario aggiungere una dichiarazione di classe foward per impedire la visualizzazione di eventuali avvisi del compilatore. Questi sono compiti che dovresti avere familiarità con ora.
- (vuoto) saveBookmark: (Segnalibro *) segnalibro // Salva segnalibro NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; if (baseURL) NSURL * documentsURL = [baseURL URLByAppendingPathComponent: @ "Documenti"]; NSURL * documentURL = [documentsURL URLByAppendingPathComponent: [NSString stringWithFormat: @ "Segnalibro _% @ -% f", segnalibro.name, [[Data NSDate] timeIntervalSince1970]]]; BookmarkDocument * document = [[BookmarkDocument alloc] initWithFileURL: documentURL]; document.bookmark = segnalibro; // Aggiungi segnalibro ai segnalibri [self.bookmarks addObject: document]; // Reload Table View [self.tableView reloadData]; [documento saveToURL: documentURL forSaveOperation: UIDocumentSaveForCreating completionHandler: ^ (BOOL successo) if (successo) NSLog (@ "Salva riuscito"); else NSLog (@ "Save failed."); ];
L'ultimo pezzo mancante del puzzle è la cancellazione dei segnalibri. Questo è molto facile rispetto a quello che abbiamo fatto finora. Preleviamo il documento del segnalibro corretto dall'origine dati e lo comunichiamo NSFileManager
per eliminarlo dal contenitore iCloud passando l'URL corretto. Questo cancellerà anche il documento su iCloud. È così facile. Ovviamente, aggiorniamo anche l'origine dati e la vista tabella.
- (void) tableView: (UITableView *) aTableView commitEditingStyle: (UITableViewCellEditingStyle) editStyle forRowAtIndexPath: (NSIndexPath *) indexPath if (editStyle == UITableViewCellEditingStyleDelete) // Recupera documento BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row] ; // Elimina documento NSError * error = nil; if (! [[NSFileManager defaultManager] removeItemAtURL: document.fileURL error: & error]) NSLog (@ "Si è verificato un errore durante il tentativo di eliminare il documento. Errore% @ con informazioni utente% @.", error, error.userInfo); // Aggiorna segnalibri [self.bookmarks removeObjectAtIndex: indexPath.row]; // Aggiorna tabella Visualizza [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade];
In questo tutorial, abbiamo refactored la nostra applicazione per utilizzare iCloud Document Storage invece di iCloud Key-Value Storage. Anche se abbiamo rifattorizzato un bel po 'di codice, il processo è stato abbastanza semplice. Ora abbiamo un'applicazione basata su documenti che è molto più adatta per gestire grandi quantità di dati utente. I componenti di base sono presenti e l'estensione dell'applicazione richiede un piccolo sforzo da parte nostra. Si noti che la nostra applicazione è ancora un'implementazione minima di un gestore di segnalibri. Ad esempio, non vi è alcuna opzione per modificare i segnalibri. Inoltre, dovremmo eseguire più verifiche degli errori se vogliamo rendere la nostra applicazione un'applicazione affidabile e affidabile pronta per il rilascio.
Avresti anche notato che abbiamo un numero di metodi