iOS 8 aggiornamenti dei dati principali e batch

Core Data è in circolazione da molti anni su OS X e non ci è voluto molto a Apple per portarlo su iOS. Anche se il framework non riceve la stessa attenzione delle estensioni o degli handoff, continua ad evolversi anno dopo anno, e quest'anno, con il rilascio di iOS 8 e OS X Yosemite, non è diverso.

Apple ha introdotto alcune nuove funzionalità nel framework Core Data, ma i più notevoli sono gli aggiornamenti batch e il recupero asincrono. Gli sviluppatori hanno richiesto queste funzionalità per molti anni e Apple ha finalmente trovato un modo per integrarle in Core Data. In questo tutorial, ti mostrerò come funzionano gli aggiornamenti batch e cosa significano per il framework Core Data.

1. Il problema

I dati principali sono ottimi per gestire i grafici degli oggetti. Anche i grafi di oggetti complessi con molte entità e relazioni non sono un grosso problema per i Core Data. Tuttavia, Core Data ha alcuni punti deboli e l'aggiornamento di un gran numero di record è uno di questi.

Il problema è facile da capire. Ogni volta che aggiorni un record, Core Data carica il record in memoria, aggiorna il record e salva le modifiche nell'archivio permanente, ad esempio un database SQLite.

Se i dati principali devono aggiornare un numero elevato di record, è necessario caricare ogni singolo record in memoria, aggiornare il record e inviare le modifiche all'archivio permanente. Se il numero di record è troppo grande, iOS verrà semplicemente salvato a causa della mancanza di risorse. Anche se un dispositivo che esegue OS X può avere le risorse per eseguire la richiesta, sarà lento e consumerà molta memoria.

Un approccio alternativo consiste nell'aggiornare i record in batch, ma anche questo richiede molto tempo e molte risorse. Su iOS 7, è l'unica opzione che gli sviluppatori iOS hanno. Questo non è più il caso su iOS 8.

2. La soluzione

Su iOS 8 e OS X Yosemite, è possibile parlare direttamente allo store persistente e dirgli cosa vorresti cambiare. Ciò in genere comporta l'aggiornamento di un attributo o l'eliminazione di un numero di record. Apple chiama questa funzionalità aggiornamenti in batch.

Ci sono un certo numero di insidie ​​a cui prestare attenzione però. I dati di base fanno un sacco di cose per te e potresti persino non realizzarlo finché non usi gli aggiornamenti in batch. La validazione è un buon esempio. Poiché Core Data esegue gli aggiornamenti batch direttamente nell'archivio permanente, ad esempio un database SQLite, Core Data non è in grado di eseguire alcuna convalida sui dati inseriti. Ciò significa che sei responsabile di assicurarti di non aggiungere dati non validi all'archivio permanente.

Quando useresti gli aggiornamenti in batch? Apple consiglia di utilizzare questa funzione solo se l'approccio tradizionale è troppo impegnativo o richiede molto tempo. Se è necessario contrassegnare centinaia o migliaia di messaggi di posta elettronica come letti, gli aggiornamenti batch sono la soluzione migliore su iOS 8 e OS X Yosemite.

3. Come funziona?

Per illustrare come funzionano gli aggiornamenti batch, suggerisco di rivedere Fine, una semplice applicazione Core Data che gestisce un elenco di cose da fare. Aggiungeremo un pulsante alla barra di navigazione che contrassegna tutti gli elementi nell'elenco come completati.

Passaggio 1: Projet Setup

Scarica o clona il progetto da GitHub e aprilo in Xcode 6. Esegui l'applicazione in iOS Simulator e aggiungi alcuni elementi da fare.

Passaggio 2: Crea elemento pulsante di barra

Aperto TSPViewController.m e dichiarare una proprietà, checkAllButton, di tipo UIBarButtonItem nell'estensione della classe privata in alto.

@interface TSPViewController ()  @property (strong, nonatomic) NSFetchedResultsController * fetchedResultsController; @property (strong, nonatomic) UIBarButtonItem * checkAllButton; @property (strong, nonatomic) Selezione NSIndexPath *; @fine

Inizializza la voce del pulsante della barra in viewDidLoad metodo del TSPViewController classe e impostarlo come elemento del pulsante della barra sinistra della voce di navigazione.

// Initialize Check All Button self.checkAllButton = [[UIBarButtonItem alloc]] initWithTitle: @ Stile "Check All": UIBarButtonItemStyleBordered target: self action: @selector (checkAll :)]; // Configure Navigation Item self.navigationItem.leftBarButtonItem = self.checkAllButton;

Passaggio 3: implementazione seleziona tutto: Metodo

Il seleziona tutto: il metodo è abbastanza facile, ma ci sono alcuni avvertimenti a cui prestare attenzione. Dai un'occhiata alla sua implementazione qui sotto.

- (void) checkAll: (id) sender // Crea descrizione entità NSEntityDescription * entityDescription = [NSEntityDescription entityForName: @ "TSPItem" inManagedObjectContext: self.managedObjectContext]; // Inizializza la richiesta di aggiornamento batch NSBatchUpdateRequest * batchUpdateRequest = [[NSBatchUpdateRequest alloc] initWithEntity: entityDescription]; // Configura la richiesta di aggiornamento batch [batchUpdateRequest setResultType: NSUpdatedObjectIDsResultType]; [batchUpdateRequest setPropertiesToUpdate: @ @ "done": @ YES]; // Esegui richiesta batch NSError * batchUpdateRequestError = nil; NSBatchUpdateResult * batchUpdateResult = (NSBatchUpdateResult *) [self.managedObjectContext executeRequest: batchUpdateRequest error: & batchUpdateRequestError]; if (batchUpdateRequestError) NSLog (@ "Impossibile eseguire la richiesta di aggiornamento batch."); NSLog (@ "% @,% @", batchUpdateRequestError, batchUpdateRequestError.localizedDescription);  else // Estrai ID oggetto NSArray * objectIDs = batchUpdateResult.result; for (NSManagedObjectID * objectID in objectIDs) // Trasforma oggetti gestiti in errori NSManagedObject * managedObject = [self.managedObjectContext objectWithID: objectID]; if (managedObject) [self.managedObjectContext refreshObject: managedObject mergeChanges: NO];  // Esegui Fetch NSError * fetchError = nil; [self.fetchedResultsController performFetch: & fetchError]; if (fetchError) NSLog (@ "Impossibile eseguire il recupero."); NSLog (@ "% @,% @", fetchError, fetchError.localizedDescription); 

Crea richiesta batch

Iniziamo creando un NSEntityDescription istanza per il TSPItem entità e usarlo per inizializzare a NSBatchUpdateRequest oggetto.

// Crea descrizione dell'entità NSEntityDescription * entityDescription = [NSEntityDescription entityForName: @ "TSPItem" inManagedObjectContext: self.managedObjectContext]; // Inizializza la richiesta di aggiornamento batch NSBatchUpdateRequest * batchUpdateRequest = [[NSBatchUpdateRequest alloc] initWithEntity: entityDescription];

Impostiamo il tipo di risultato della richiesta di aggiornamento batch su NSUpdatedObjectIDsResultType, il che significa che il risultato della richiesta di aggiornamento batch sarà una matrice contenente gli ID oggetto, istanze del NSManagedObjectID classe, dei record che sono stati modificati dalla richiesta di aggiornamento batch.

// Configura la richiesta di aggiornamento batch [batchUpdateRequest setResultType: NSUpdatedObjectIDsResultType];

Inoltre popoliamo il propertiesToUpdate proprietà della richiesta di aggiornamento batch. Per questo esempio, abbiamo impostato propertiesToUpdate ad NSDictionary contenente una chiave, @"fatto", con valore @SÌ. Questo significa semplicemente che ogni TSPItem la registrazione sarà impostata su fatto, che è esattamente ciò che vogliamo.

// Configura la richiesta di aggiornamento batch [batchUpdateRequest setPropertiesToUpdate: @ @ "done": @ YES];

Esegui richiesta di aggiornamento batch

Anche se gli aggiornamenti batch ignorano il contesto dell'oggetto gestito, l'esecuzione di una richiesta di aggiornamento batch viene effettuata chiamando ExecuteRequest: errore:NSManagedObjectContext esempio. Il primo argomento è un'istanza del NSPersistentStoreRequest classe. Per eseguire un aggiornamento batch, passiamo la richiesta di aggiornamento batch appena creata. Questo funziona pinne dal NSBatchUpdateRequest la classe è a NSPersistentStoreRequest sottoclasse. Il secondo argomento è un puntatore a un NSError oggetto.

// Esegui richiesta batch NSError * batchUpdateRequestError = nil; NSBatchUpdateResult * batchUpdateResult = (NSBatchUpdateResult *) [self.managedObjectContext executeRequest: batchUpdateRequest error: & batchUpdateRequestError];

Aggiornamento del contesto dell'oggetto gestito

Come accennato in precedenza, gli aggiornamenti batch ignorano il contesto dell'oggetto gestito. Ciò fornisce agli aggiornamenti in batch la loro potenza e velocità, ma significa anche che il contesto dell'oggetto gestito non è a conoscenza delle modifiche apportate. Per rimediare a questo problema, dobbiamo fare due cose:

  • trasformare gli oggetti gestiti che sono stati aggiornati dall'aggiornamento batch in errori
  • dire al controller risultati recuperati per eseguire un recupero per aggiornare l'interfaccia utente

Questo è quello che facciamo nelle prossime righe del seleziona tutto: metodo. Per prima cosa controlliamo se la richiesta di aggiornamento batch ha avuto successo controllando il batchUpdateRequestError per zero. Se ha successo, estraiamo la matrice di NSManagedObjectID istanze dal NSBatchUpdateResult oggetto.

// Estrai ID oggetto NSArray * objectIDs = batchUpdateResult.result;

Quindi iteriamo sopra il objectIds array e chiedere il contesto dell'oggetto gestito per il corrispondente NSManagedObject esempio. Se il contesto dell'oggetto gestito restituisce un oggetto gestito valido, lo trasformiamo in un errore invocando refreshObject: mergeChanges:, passare l'oggetto gestito come primo argomento. Per forzare l'oggetto gestito in un errore, passiamo NO come secondo argomento.

// Estrai ID oggetto NSArray * objectIDs = batchUpdateResult.result; for (NSManagedObjectID * objectID in objectIDs) // Trasforma oggetti gestiti in errori NSManagedObject * managedObject = [self.managedObjectContext objectWithID: objectID]; if (managedObject) [self.managedObjectContext refreshObject: managedObject mergeChanges: NO]; 

Recupero dei record aggiornati

L'ultimo passo è dire al controller dei risultati recuperato di eseguire un recupero per aggiornare l'interfaccia utente. Se questo non ha successo, registriamo l'errore corrispondente.

// Esegui Fetch NSError * fetchError = nil; [self.fetchedResultsController performFetch: & fetchError]; if (fetchError) NSLog (@ "Impossibile eseguire il recupero."); NSLog (@ "% @,% @", fetchError, fetchError.localizedDescription); 

Anche se questo può sembrare complicato e abbastanza complesso per una facile operazione, tieni presente che ignoriamo lo stack dei Core Data. In altre parole, dobbiamo occuparci di alcune operazioni di manutenzione che vengono solitamente eseguite da Core Data.

Step 4: Build & Run

Costruisci il progetto ed esegui l'applicazione in iOS Simulator o su un dispositivo fisico. Fare clic o toccare l'elemento del pulsante della barra sulla destra per controllare ogni elemento delle attività nell'elenco.

Conclusione

Gli aggiornamenti batch sono una grande aggiunta al framework Core Data. Non solo risponde a un'esigenza che gli sviluppatori hanno avuto per molti anni, non è difficile da attuare a patto di tenere a mente alcune regole di base. Nel prossimo tutorial, daremo un'occhiata più da vicino al recupero asincrono, un'altra nuova funzionalità del framework Core Data.