Păstrarea sincronizării datelor aplicațiilor pe toate dispozitivele este o sarcină complexă și descurajantă. Din fericire, acesta este exact motivul pentru care Apple a construit iCloud. În această serie Tuts + Premium, veți afla cum funcționează iCloud și modul în care aplicațiile dvs. pot partaja cu ușurință datele pe mai multe dispozitive.
În cea de-a doua tranșă a acestei serii, v-am arătat cum să folosiți spațiul de stocare cheie al lui iCloud pentru a păstra cantități mici de date de utilizator sincronizate pe mai multe dispozitive. Chiar dacă stocarea cheie-valoare este ușor de utilizat și de adoptat, una dintre dezavantaje este limitarea pe care o reprezintă cu privire la cantitatea de date care pot fi stocate. Rețineți că fiecare aplicație poate să stocheze doar 1 MB de date, iar numărul de perechi de chei-valoare este limitat la 1024. După cum am menționat la sfârșitul tutorialului anterior, managerul de marcaje s-ar putea întâlni în această limitare dacă vreunul dintre utilizatorii noștri vor să stocheze o mulțime de marcaje.
Soluția la această problemă este trecerea de la spațiul de stocare iCloud Key-Value la iCloud Document Storage pentru stocarea marcajelor. În ceea ce privește spațiul pe disc, iCloud Document Storage este limitată numai de spațiul de stocare iCloud al utilizatorului. Știind că un cont gratuit vine cu stocarea de date de 5 GB, iCloud Document Storage este soluția ideală pentru managerul de marcaje. În acest tutorial, vom refactor managerul de marcaje de la utilizarea iCloud Key-Value Storage la adoptarea iCloud Document Storage.
Aș dori să subliniez că este important să citiți prima și a doua tranșă din această serie înainte de a citi această piesă. În acest tutorial, vom refactor managerul nostru de marcaje bazându-ne pe fundațiile pe care le-am pus în partea a doua a seriei.
UIDocument
Odată cu introducerea iCloud, Apple a făcut și el UIDocument
disponibil pentru dezvoltatori. Inginerii de la Apple au creat UIDocument
cu iCloud în minte. UIDocument
face integrarea iCloud pentru aplicația bazată pe documente mult mai ușoară. Cu toate acestea, este important să rețineți că UIDocument
are mult mai mult decât furnizarea unui ușor de utilizat API pentru integrarea iCloud.
Aplicațiile bazate pe documente trebuie să se ocupe de o serie de provocări, cum ar fi: (1) citirea și scrierea datelor de pe și pe disc fără blocarea interfeței cu utilizatorul, (2) salvarea datelor pe disc la intervale adecvate și (3) opțional integrarea cu iCloud. UIDocument
oferă soluții integrate pentru aceste provocări.
Înainte de a începe să lucrăm UIDocument
, Vreau să clarific ce UIDocument
este și ce nu este. UIDocument
este un obiect de controler care gestionează unul sau mai multe modele la fel UIViewController
controlează și gestionează una sau mai multe vizualizări. UIDocument
nu stochează date, ci gestionează obiectele model care dețin datele utilizatorului. Acesta este un concept important de înțeles, care va deveni mai clar atunci când vom începe refactorizarea cererii noastre de utilizare UIDocument
.
Un alt concept important de înțeles este modul în care operațiile de citire și scriere funcționează atunci când se utilizează UIDocument
. Dacă decideți să utilizați UIDocument
în aplicația dvs., nu trebuie să vă faceți griji cu privire la blocarea firului principal atunci când citiți sau scrieți date pe disc. Atunci când se utilizează UIDocument
, sistemul de operare va gestiona automat o serie de sarcini pentru dvs. pe o coadă de fundal și va asigura că firul principal rămâne receptiv. Aș dori să iau un moment și să explic mai detaliat fiecare operațiune pentru a vă oferi o bună înțelegere a diferitelor părți mobile care sunt implicate.
Să începem cu citirea datelor de pe disc. Operația de citire începe printr-o operație deschisă inițiată pe coada de apelare. Operația deschisă este inițiată atunci când se deschide un document prin trimiterea unui mesaj de openWithCompletionHandler:. Transmitem un handler de terminare care este invocat când întreaga operație de citire este terminată. Acesta este un aspect important al operațiilor de citire și scriere. Poate dura o perioadă netrivială de timp pentru a citi sau scrie datele de pe sau pe disc și nu vrem să facem acest lucru pe firul principal și să blocăm interfața cu utilizatorul. Operația reală de citire are loc într-o coadă de fundal gestionată de sistemul de operare. Când operația de citire se termină, loadFromContents: ofType: eroare: metoda este solicitată pe document. Această metodă trimite UIDocument
datele necesare inițializării modelului (modelelor) pe care le administrează. Instrumentul de completare este invocat atunci când acest proces se termină, ceea ce înseamnă că putem răspunde la încărcarea documentului, de exemplu prin actualizarea interfeței cu conținutul documentului.
Operația de scriere este similară. Începe cu o operație de salvare inițiată în coada de așteptare prin trimitere saveToURL: forSaveOperation: completionHandler: la obiectul documentului. Ca și în operația de citire, trecem printr-un handler de terminare care este invocat când operația de scriere se termină. Scrierea datelor pe disc are loc într-o coadă de fundal. Se cere sistemul de operare UIDocument
pentru un instantaneu al datelor modelului prin trimiterea unui mesaj contentsForType: eroare:. Instrumentul de completare este invocat atunci când operația de scriere termină, ceea ce ne oferă posibilitatea de a actualiza interfața cu utilizatorul.
UIDocument
este o clasă de bază și nu este menită a fi utilizată direct. Avem nevoie de subclasă UIDocument
și să o adaptăm la nevoile noastre. Cu alte cuvinte, noi subclasa UIDocument
astfel încât să știe despre modelul nostru și cum să o gestionăm. În forma sa cea mai de bază, subclasarea UIDocument
doar ne cere să suprascriem loadFromContents: ofType: eroare: pentru citire și contentsForType: eroare: pentru scris.
Confuz? Ar trebui să fii. Chiar dacă UIDocument
face viata mult mai usoara, este o clasa avansata si avem de-a face cu un subiect complex. Cu toate acestea, sunt convins că veți obține o bună înțelegere a aplicațiilor bazate pe documente odată ce ne-am refactat cererea.
Înainte de a continua, vreau să clarific care sunt scopurile noastre pentru acest tutorial. Scopul principal este refactorizarea aplicației noastre pentru a utiliza iCloud Document Storage în loc de stocarea cheie iCloud Key-Value Storage. Asta înseamnă că vom face uz UIDocument
și subclasa pentru a se potrivi nevoilor noastre. În plus, vom crea o clasă de model personalizată pentru marcajul nostru care va fi utilizat și gestionat de către UIDocument
subclasă.
În prezent, aplicația noastră este configurată să folosească numai spațiul de stocare cheie. Pentru a activa stocarea documentelor, trebuie mai întâi să configurați drepturile aplicației. Deschide Editorul țintă prin selectarea aplicației noastre în Project Navigator și selectați singura țintă din lista de destinații. În drepturi secțiune, ar trebui să vedeți Conectori iCloud de mai jos iCloud Key-Value Store. Lista de lângă Conectori iCloud este gol momentan. Faceți clic pe butonul plus din partea de jos a listei și veți vedea că Xcode creează un identificator de container iCloud pentru dvs., care se potrivește cu identificatorul pachetului aplicației.
Ce este un container iCloud? După cum sugerează și numele, acesta este un container în memoria de stocare a datelor iCloud a utilizatorului. Prin specificarea unuia (sau mai multor) containere iCloud în fișierul de drepturi al aplicației, îi spunem sistemului de operare ce containere are accesul aplicației noastre.
În tutorialul anterior, am stocat fiecare marcaj ca o instanță NSDictionary
, dar aceasta nu este o soluție bună pentru o aplicație bazată pe documente. În schimb, vom crea o clasă de marcaje personalizate care ne va permite să arhivăm cu ușurință datele sale.
Creaza un nou NSObject
subclasa prin alegerea Fişier din meniu, selectând Nou, și apoi Fişier… . Selectați Cocoa Touch din panoul din stânga și alegeți Clasa obiectiv-C din lista de șabloane din dreapta. Dați clasei un nume de semn de carte și asigurați-vă că este o subclasă de NSObject. Specificați locul în care doriți să salvați noua clasă și loviți-o Crea.
În fișierul de antet al modelului nostru, adăugăm cele două proprietăți ale modelului de marcaj pe care l-am utilizat în tutorialul anterior, a Nume și a URL-. Ambele proprietăți sunt instanțe de NSString
. De asemenea, declarăm un inițializator desemnat, care ia ca parametri un nume și o adresă URL. În cele din urmă, este important să ne asigurăm că semn de carte
clasa este conformă cu NSCoding
protocol.
#import@ interfață Bookmark: NSObject NSString * _name; NSString * _url; @property (nonatomic, copy) NSString * nume; @property (nonatomic, copie) NSString * url; - (id) initWithName: (NSString *) nume șiURL: (NSString *) url; @Sfârșit
În fișierul de implementare al modelului nostru, definim mai întâi două constante pentru numele și URL-ul marcajului. Aceasta este o practică bună, deoarece va reduce la minimum șansa de a incripționa cheile pe care le vom folosi în curând. Apoi implementăm metoda de inițializare. Această metodă este simplă. Inițializăm instanța noastră și atribuim numele și adresa URL variabilelor instanței de marcaj.
Partea importantă este de a implementa metodele necesare pentru a face semn de carte
clasa este conformă cu NSCoding
protocol. În cazul în care NSCoding
protocolul este nou pentru tine, atunci vă încurajez să citiți Ghidul de Programare a Arhivelor și Serializărilor deoarece acesta este un subiect important pentru orice dezvoltator de Cocoa-Touch. În esență, este faptul că NSCoding
protocol ne permite să arhivăm cu ușurință și să ne arhiveze instanțele semn de carte
clasă.
#import "Bookmark.h" #define kBookmarkName @ "Nume marcaj" #define kBookmarkURL @ "Marcaj URL" @implementation Marcaj @synthesize name = _name, url = _url; #pragma - marca #pragma Inițializare - (id) initWithName: (NSString *) nume șiURL: (NSString *) url self = [super init]; dacă auto.name = nume; auto.url = url; întoarce-te; #pragma marcă - #pragma marca NSCoding Protocol - (void) encodeWithCoder: (NSCoder *) coder [coder encodeObject: auto.name pentruKey: kBookmarkName]; [coder encodeObject: self.url forKey: kBookmarkURL]; - (id) initWithCoder: (codul NSCoder *) self = [super init]; dacă (sine! = nil) auto.name = [coder decodeObjectForKey: kBookmarkName]; self.url = [coder decodeObjectForKey: kBookmarkURL]; întoarce-te; @Sfârșit
subclasarea UIDocument
nu este la fel de dificil cum credeai. După cum am menționat mai devreme, tot ceea ce trebuie să facem este să suprascrieți două metode și să creați o proprietate pentru modelul de marcaj pe care îl va gestiona.
Creați o nouă clasă la fel ca și noi semn de carte
și dați-i un nume de BookmarkDocument
. Asigurați-vă că este o subclasă de UIDocument
. În fișierul antetului nostru UIDocument
subclasa, adăugăm o declarație în avans pentru semn de carte
clasă și vom crea o proprietate pentru modelul nostru de marcaje. Nu uitați să sintetizați accesoriile pentru această proprietate.
#import@class Bookmark; @ interfață BookmarkDocument: UIDocument Bookmark * _bookmark; @property (nonatomic, strong) Bookmark * bookmark; @Sfârșit
În fișierul de implementare vom importa fișierul antet al semn de carte clasă și să definească o altă constantă pentru a servi drept cheie pentru arhivarea și dezarhivarea modelului de marcaj. După cum am menționat mai devreme, trebuie doar să ignorăm două metode în UIDocument subclasa, (1) loadFromContents: ofType: eroare: și (2) contentsForType: eroare:. Prima metodă va fi invocată când vom deschide un document, în timp ce a doua metodă va fi invocată atunci când un document este salvat. Ambele metode sunt numite de sistemul de operare. Nu trebuie să chemăm direct aceste mehoduri.
#import "BookmarkDocument.h" #import "Bookmark.h" #define kArchiveKey @ "Marcaj" @implementare BookmarkDocument @synthesize bookmark = _bookmark;
Lasă-mă să te trec pe aici loadFromContents: ofType: eroare:. Primul argument este cuprins de tip id
. Aceasta poate fi fie o instanță NSData
sau NSFileWrapper
. Acesta din urmă este valabil numai atunci când aplicația folosește pachete de fișiere. În cazul nostru, ne putem aștepta NSData
instanță. Mai întâi verificăm dacă lungimea NSData
exemplu nu este egal cu zero. Inițializăm un exemplu de NSKeyedUnarchiver
și să o furnizeze cu cuprins obiect. Prin decodarea datelor, primim o instanță a semn de carte
clasă înapoi. Acesta este motivul pentru care semn de carte
clasa este conformă cu NSCoding
protocol. Dacă lungimea lui NSData
instanța este egală cu zero, inițializăm un nou marcaj cu valori implicite pentru nume și adresă URL. Rețineți că ne întoarcem DA
la sfârșitul metodei.
- (BOOL) loadFromContents: (id) conținutulType: (NSString *) typeName eroare: (NSError * __ autoreleasing *) outError if ([lungimea conținutului]> 0) NSKeyedUnarchiver * unarchiver = [NSKeyedUnarchiver alloc] initForReadingWithData: content; self.bookmark = [unarchiver decodeObjectForKey: kArchiveKey]; [finalizareDescriere definitivă]; altceva self.bookmark = [Bookmark Bookmark] initWithName: @ "Nume de marcaj" șiURL: @ "www.example.com"]; reveniți DA;
contentsForType: eroare: metoda face contrariul. Adică, furnizăm datele care trebuie să fie scrise pe disc. Acest obiect de date este așa-numita imagine a datelor noastre de model. Facem acest lucru inițializând un exemplu de NSMutableData
și folosiți aceasta pentru a inițializa o instanță a NSKeyedArchiver
. Apoi putem arhiva instanța de marcaj astfel încât să poată fi scrisă pe disc. Această metodă ne așteaptă să revenim la o instanță NSData
și asta este exact ceea ce facem. Al nostru UIDocument
subclasa este acum pregătită pentru noi.
- (id) contentForType: (NSString *) tipName eroare: (NSError * __ autoreleasing *) outError NSMutableData * data = [[NSMutableData alinia] init]; NSKeyedArchiver * arhivator = [[NSKeyedArchiver alocare] initForWritingWithMutableData: date]; [archiver encodeObject: auto.bookmark pentruKey: kArchiveKey]; [finishingEncoding]; returnează datele;
Există patru elemente ale aplicației noastre care trebuie reconfigurate dacă vrem să folosim iCloud Document Storage:
(1) încărcarea, (2) afișarea, (3) salvarea și (4) ștergerea marcajelor. Să începem cu încărcarea marcajelor.
Înainte să aruncăm o privire la loadBookmarks metoda, trebuie să declarăm o proprietate privată, o instanță NSMetadataQuery
. Va deveni clar de ce trebuie să facem acest lucru în doar câteva minute. Nu uitați să adăugați două declarații suplimentare de import în fișierul de implementare al controlorului nostru de vizualizare, unul pentru semn de carte
clasa și una pentru BookmarkDocument
clasă.
#import "ViewController.h" #import "Bookmark.h" #import "BookmarkDocument.h" #import "AddBookmarkViewController.h" @interface ViewController () NSMetadataQuery * _query; interogare @property (nonatomică, puternică) NSMetadataQuery *; @end @implementation ViewController @synthesize bookmarks = _bookmarks; @synthesize tableView = _tableView; @synthesize query = _query;
In loc de NSDictionary
instanțele, matricea de marcaje, sursa de date din tabelul nostru va conține instanțe ale BookmarkDocument
clasă. Să aruncăm o privire la refactat loadBookmarks metodă. Începem prin inițializarea matricei de marcaje. Apoi, cerem NSFileManager
pentru URL-ul containerului iCloud vom folosi pentru a stoca marcajele noastre. Nu fi aruncat de numele colorat al acestei metode. URLForUbiquityContainerIdentifier: acceptă un argument, identificatorul containerului iCloud la care vrem să obținem acces. Prin trecerea nulului ca argument, NSFileManager
va selecta automat primul container iCloud declarat în fișierul de drepturi al aplicației. Rețineți că dacă specificați un identificator de container iCloud, trebuie să furnizați și identificatorul echipei. Formatul corect este
- (void) loadBookmarks if (! self.bookmarks) auto.bookmarks = [[NSMutableArray aloca] init]; NSURL * baseURL = [[NSFileManager implicitManager] URLForUbiquityContainerIdentifier: nil]; dacă (baseURL) self.query = [[NSMetadataQuery alloc] init]; [auto.query setSearchScopes: [NSArray arrayWithObject: NSMetadataQueryUbiquitousDocumentsScope]]; NSPredicate * predicate = [N predicție predictivăWithFormat: @ "% K ca '*'", NSMetadataItemFSNameKey]; [auto.query setPredicate: predicat]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; [nc addObserver: selector auto: @selector (queryDidFinish :) nume: NSMetadataQueryDidFinishGatheringNotification object: self.query]; [nc addObserver: selector auto: @selector (queryDidUpdate :) nume: NSMetadataQueryDidUpdateNotification object: self.query]; [self.query startQuery];
Această metodă nu este doar pentru a afla unde putem stoca documentele noastre iCloud. Apelând cu succes această metodă, sistemul de operare va extinde caseta de nisip a aplicației noastre pentru a include directorul containerului iCloud pe care l-am specificat. Aceasta înseamnă că trebuie să apelăm această metodă înainte de a începe citirea sau scrierea datelor în acest director. Dacă ar trebui să înregistrați URL-ul returnat în consolă, ați observa două ciudățenii, (1) adresa URL returnată pentru containerul iCloud este o adresă URL locală (localizată pe dispozitivul însuși) și (2) această adresă URL locală nu este localizată în nisipul aplicației noastre. Modul în care funcționează iCloud este că stocăm documentele pe care le vom stoca în iCloud în acest director local care NSFileManager
ne oferă. Daemonul iCloud, care rulează pe dispozitivul nostru în fundal, va avea grijă de aspectul sincronizării documentelor și va face acest lucru chiar dacă aplicația noastră nu rulează.
Deoarece adresa URL locală trăiește în afara casetei de nisip a aplicației noastre, trebuie să invocăm această metodă înainte de a citi sau a scrie în acest director. Invocând această metodă, solicităm sistemului de operare permisiunea de a citi și de a scrie în acest director.
Să continuăm să disecăm loadBookmarks metodă. Verificăm adresa URL la care ne întoarcem NSFileManager
nu este egal cu zero. Acesta din urmă implică două lucruri importante, (1) avem o locație pe care o putem citi și scrie (2) iCloud este activată pe dispozitiv. Al doilea punct este deosebit de important, deoarece nu toate dispozitivele vor avea activat iCloud.
Dacă NSFileManager
a returnat într-adevăr un URL valid, inițializăm o instanță de NSMetadataQuery
și alocați-o variabilei de instanță pe care am declarat-o mai devreme. NSMetadataQuery
ne permite să căutăm în containerul iCloud documente. După inițializarea unei instanțe din NSMetadataQuery
, specificăm domeniul de căutare al nostru. În cazul nostru, vom căuta în Documente directorul containerului nostru iCloud, deoarece acesta este locul în care vom stoca documentele de marcaj. Puteți rafina interogarea prin setarea unui predicat de căutare. Dacă sunteți familiarizat cu datele de bază, atunci acest lucru nu este nou pentru dvs. Căutarea noastră va fi simplă, vom căuta toate documentele din directorul de documente al containerului nostru iCloud, de unde și asteriscul din predicat.
Înainte de a începe interogarea noastră, este important să ne dăm seama că nu ar trebui să ne așteptăm la un rezultat imediat din interogarea noastră. În schimb, vom înregistra controlorul nostru de vedere ca observator pentru NSMetadataQueryDidUpdateNotification
și NSMetadataQueryDidFinishGatheringNotification
cu instanța noastră de interogare ca expeditor. Aceasta înseamnă că vom fi notificați când interogarea noastră a returnat rezultate sau când rezultatele vor fi actualizate. În cele din urmă, vom începe interogarea.
Este important să păstrăm o referință la instanța de interogare pentru a împiedica eliberarea acesteia. Acesta este motivul pentru care controlerul nostru de vizualizare păstrează o referință la interogare (ca variabilă de instanță) atât timp cât interogarea se execută.
Să aruncăm o privire la queryDidFinish: și queryDidUpdate: metodele de retur a apelurilor de notificare pentru a vedea cum să gestionați rezultatele interogării. Ambele metode transmit obiectul expeditorului notificării, NSMetadataQuery
exemplu, la o metodă convenabilă, processQueryResults:. Când ne uităm la această metodă, vom vedea că vom începe mai întâi prin dezactivarea actualizărilor pentru interogare. Acest lucru este important deoarece rezultatele interogării pot primi actualizări live atunci când au loc schimbări și trebuie să prevenim acest lucru atâta timp cât procesăm rezultatele interogării. Apoi, eliminăm toate obiectele din matricea de marcaje și enumerăm rezultatele interogării. Fiecare element din matricea rezultate este o instanță de NSMetadataItem
, care conține metadatele asociate fiecărui document de marcaj, inclusiv adresa URL a fișierului de care avem nevoie pentru a deschide documentul. Solicităm fiecare element de metadate pentru adresa URL a fișierului și inițializăm documentul respectiv.
Rețineți că inițializarea unui document de marcaj nu înseamnă că l-am încărcat de pe disc. Amintiți-vă că acest lucru se face prin trimiterea documentului nostru de marcare un mesaj de openWithCompletionHandler:. Dacă operația deschisă este reușită și documentul este încărcat, îl adăugăm la seria de marcaje și îl afișăm în vizualizarea tabelului. În cele din urmă, trebuie să eliminăm controlorul de vedere ca observator, deoarece nu mai trebuie să primim notificări în acest moment.
- (void) queryDidFinish: (NSNotification *) notificare NSMetadataQuery * query = [obiect de notificare]; // Opriți actualizările [query disableUpdates]; // Stop Query [interogare stopQuery]; // Eliminați marcajele [self.bookmarks removeAllObjects]; [query.results enumerateObjectsUsingBlock: ^ (id id, NSUInteger idx, BOOL * stop) NSURL * documentURL = [(NSMetadataItem *) valoarea objForAttribute: NSMetadataItemURLKey]; BookmarkDocument * document = [[BookmarkDocument alocare] initWithFileURL: documentURL]; [document openWithCompletionHandler: ^ (succesul BOOL) if (succes) [self.bookmarks addObject: document]; [self.tableView reloadData]; ]; ]; [[NSNotificationCenter defaultCenter] removeObserver: auto];
Codul de afișare a marcajelor din tabelul nostru nu trebuie să schimbe prea mult. În loc să preluați corect NSDictionary
de exemplu, din sursa de date, vom prelua o instanță a BookmarkDocument
clasă. Accesul la numele și adresa URL a marcajului trebuie actualizat, de asemenea.
- (UITableViewCell *) tableView: (UITableView *) aTableView cellForRowAtIndexPath: (NSIndexPath *) indexPath NSString static * CellIdentifier = @ "Cell Identifier"; UITableViewCell * celula = [aTableView dequeueReusableCellWithIdentifier: CellIdentifier]; dacă (celula == zero) cell = [[UITableViewCell alin] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: CellIdentifier]; // Fetch Bookmark BookmarkDocument * document = [auto.bookmarks objectAtIndex: indexPath.row]; // Configure Cell celula.textLabel.text = document.bookmark.name; cell.detailTextLabel.text = document.bookmark.url; celule retur;
Mergeți la Salvați: metoda în AddBookmarkViewController. În loc să creați o NSDictionary
și trimițând-o la controlorul nostru principal, creăm un nou semn de carte
instanță. Asta e. Restul este tratat în saveBookmark: metodă a controlerului nostru principal de vizualizare. Nu uitați să adăugați o declarație de import pentru semn de carte
clasă.
- (IBAction) salvați: (id) expeditor Bookmark * bookmark = [[Alocare rezervă] initWithName: self.nameField.text șiURL: self.urlField.text]; [self.viewController saveBookmark: marcaj]; [self dismissViewControllerAnimated: DA finalizat: zero];
Salvarea unui marcaj în containerul nostru iCloud este aproape la fel de simplu ca salvarea acestuia în caseta de nisip a aplicației noastre. În primul rând, cerem NSFileManager
pentru URL-ul containerului nostru iCloud, așa cum am făcut-o mai devreme. Pe baza acestei adrese URL, construim adresa URL corectă pentru salvarea documentului de marcaj în Documente directorul containerului iCloud. Numele documentului nostru poate fi orice dorim să fie atâta timp cât numele său este unic. Am ales să utilizez numele marcajului și o marcă de timp. Utilizatorul nu va vedea acest nume de fișier, astfel încât numele nu este atât de important. Ceea ce este important este că este unic.
Avem o instanță de marcaj, dar încă nu avem un document de marcaj. Creați un nou document de marcare inițializându-l cu adresa URL pe care tocmai l-am construit. Apoi, atribuim noul nostru marcaj proprietății marcajului documentului. În final, adăugăm documentul în matricea de marcaje și reîncărcați vizualizarea tabelului.
Salvarea documentului în containerul iCloud este ușoară. Inițiem operațiunea de salvare despre care am vorbit mai devreme prin trimiterea noului nostru document la mesaj saveToURL: forSaveOperation: completionHandler:. Al doilea parametru al acestei metode specifică tipul operației de salvare. În cazul nostru, trecem UIDocumentSaveForCreating
, ceea ce înseamnă crearea unui nou document de marcaj. Deoarece nu avem nevoie să facem ceva special în exemplul nostru, pur și simplu logăm un mesaj la consola când termină operația de salvare.
S-ar putea să fi observat că declarația noastră de metodă sa schimbat ușor. Nu mai trecem de o instanță NSDictionary
ca singurul argument. În schimb, trecem printr-o instanță a semn de carte
clasă. Asigurați-vă că actualizați fișierul antet pentru a reflecta această modificare. De asemenea, va trebui să adăugați o declarație de clasă foward pentru a împiedica apariția avertismentelor compilatorului. Acestea sunt sarcini pe care ar trebui să le cunoașteți până acum.
- (void) saveBookmark: (Marcaj *) marcaj // Salvează marcajul NSURL * baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil]; dacă (baseURL) NSURL * documentsURL = [baseURL URLByAppendingPathComponent: @ "Documente"]; NSURL * documentURL = [documentsURL URLByAppendingPathComponent: [NSString stringWithFormat: @ "Bookmark _% @ -% f", bookmark.name, [[NSDate date] timeIntervalSince1970]]]; BookmarkDocument * document = [[BookmarkDocument alocare] initWithFileURL: documentURL]; document.bookmark = marcaj; / / Adauga marcajul la marcaje [self.bookmarks addObject: document]; // Reîncarcă tabelul [self.tableView reloadData]; [document saveToURL: documentURL forSaveOperation: UIDocumentSaveForCrearea completăHandler: ^ (succes BOOL) if (succes) NSLog (@ "Salvare a reușit."); altceva NSLog (@ "Salvarea a eșuat."); ];
Ultima piesă lipsă a puzzle-ului este ștergerea marcajelor. Acest lucru este foarte ușor în comparație cu ceea ce am făcut până acum. Atragem documentul de marcaj corect din sursa de date și spunem NSFileManager
să îl ștergeți din containerul iCloud prin trecerea adresei URL corecte. Acest lucru va șterge, de asemenea, documentul de pe iCloud. Atât de ușor este. Bineînțeles, actualizăm și sursa de date și tabelul de vizualizare.
- (void) tableView: (UITableView *) aTableView commitEditingStyle: (UITableViewCellEditingStyle) editareStyle forRowAtIndexPath: (NSIndexPath *) indexPath if (editingStyle == UITableViewCellEditingStyleDelete) // Retur document BookmarkDocument * document = [self.bookmarks objectAtIndex: indexPath.row] ; // Șterge documentul NSError * error = nil; dacă [! [[NSFileManager defaultManager] removeItemAtURL: eroare document.fileURL: & eroare]) NSLog (@ "A apărut o eroare în timp ce încercați să ștergeți documentul. // Actualizați marcajele [self.bookmarks removeObjectAtIndex: indexPath.row]; // Actualizați vizualizarea tabelului [aTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] cuRowAnimation: UITableViewRowAnimationFade];
În acest tutorial am redactat aplicația noastră de a utiliza iCloud Document Storage în loc de iCloud Key-Value Storage. Chiar dacă am reluat destul de puțin cod, procesul a fost destul de simplu. Acum avem o aplicație bazată pe documente care este mult mai potrivită pentru manipularea unor cantități mai mari de date de utilizator. Componentele de bază sunt în vigoare și extinderea aplicației necesită puțin efort din partea noastră. Rețineți că aplicația noastră este încă o implementare minimală a unui manager de marcaje. De exemplu, nu există nicio opțiune pentru editarea marcajelor. De asemenea, ar trebui să facem mai multe verificări de eroare dacă vrem să facem aplicația noastră într-o aplicație robustă și fiabilă care este gata de lansare.
De asemenea, ați fi observat că avem o serie de metode de care nu mai avem nevoie. Am eliminat aceste metode din eșantionul de cod final și vă sugerez să faceți același lucru. Eliminarea codului învechit este, de asemenea, o parte a procesului de refactorizare și este esențială atunci când doriți să păstrați codul dvs. menținut.
În acest tutorial, am analizat cu atenție iCloud Document Storage, precum și UIDocument
clasă. În tutorialul următor, vom mări imaginea UIManagedDocument
, o subclasă discretă de UIDocument
concepute pentru a colabora îndeaproape cu datele de bază.