{"id":5380,"date":"2010-12-23T11:41:13","date_gmt":"2010-12-23T10:41:13","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=5380"},"modified":"2010-12-23T11:41:13","modified_gmt":"2010-12-23T10:41:13","slug":"t082-guida-alluso-di-core-data-parte-2","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t082-guida-alluso-di-core-data-parte-2\/","title":{"rendered":"T#082 &#8211; Guida all&#8217;uso di Core Data (Parte 2)"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/t081-usare-core-data-iphone-ipad-00.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/t081-usare-core-data-iphone-ipad-00.png\" alt=\"t081-usare-core-data-iphone-ipad-00\" title=\"t081-usare-core-data-iphone-ipad-00\" width=\"87\" height=\"66\" class=\"alignleft size-full wp-image-5302\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/t081-usare-core-data-iphone-ipad-00.png 382w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/t081-usare-core-data-iphone-ipad-00-300x229.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/t081-usare-core-data-iphone-ipad-00-150x114.png 150w\" sizes=\"auto, (max-width: 87px) 100vw, 87px\" \/><\/a> Eccoci alla seconda puntata della nostra Guida all&#8217;uso di Core Data nelle nostre applicazioni iPhone e iPad.<br \/>\nNe approfitto per augurare Buon Natale a tutti \ud83d\ude42<\/p>\n<p>&nbsp;<\/p>\n<p><strong>In questo episodio:<\/strong><\/p>\n<ul>\n<li>Core Data vs Database: le differenze<\/li>\n<li>Aggiungiamo al nostro programma la possibilit\u00e0 di modificare ed eliminare i record<\/li>\n<li>Sfruttiamo la procedura automatica per creare le nostre classi Model, che ereditano da <strong>NSManagedObject<\/strong>, per non dover ricorrere continuamente al <strong>KVC<\/strong>.<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h4>1. Core Data vs Database<\/h4>\n<p>Come abbiamo detto nella scorsa puntata, <strong>Core Data non \u00e8 un database<\/strong>.<br \/>\nQuest&#8217;affermazione a prima vista potrebbe dare la stessa sensazione di dissonanza cognitiva di <em>&#8220;Ceci n&#8217;est pas une pipe&#8221;<\/em>, quindi \u00e8 il caso di approfondire.<\/p>\n<p>Il primo istinto, una volta data un&#8217;occhiata ai metodi disponibili, \u00e8 quello di usarlo come un database, cio\u00e9 fetch\/manipola i dati\/salvataggio, che poi \u00e8 quello che facciamo in questo tutorial. Questo perch\u00e9 il nostro Model \u00e8 molto semplice. Ma Core Data brilla soprattutto nella gestione di oggetti e rapporti fra oggetti anche molto complicati.<\/p>\n<p>Il concetto fondamentale \u00e8 che Core Data pu\u00f2 avere SQLite come backend, ma non \u00e8 semplicemente un wrapper.<br \/>\nPassando attraverso Core Data otteniamo delle funzionalit\u00e0 di gestione dei rapporti fra le Entit\u00e0 che, come vedremo pi\u00f9 avanti in questo tutorial, sono autentici oggetti objective-C, sottoclassi di NSManagedObject: ci\u00f2 significa che <em>dobbiamo istanziarli prima di poter agire su di loro<\/em>.<\/p>\n<p>Core Data funzionerebbe anche senza backend, anche se in questo caso rinunceremmo alla persistenza dei dati: possiamo operare completamente in ram, se istanziamo tutti i record e li colleghiamo fra di loro possiamo arrivare a tutti i record senza usare ricerche e senza accedere al disco.<br \/>\nManipolare oggetti in ram \u00e8 pi\u00f9 rapido che aggiornare un database, quando salviamo i dati del nostro contesto allora Core Data user\u00e0 il database e quindi i tempi di salvataggio di Core Data si sommeranno a quelli del database.<\/p>\n<p>Riassumiamo in una lista le caratteristiche dei database e di Core Data.<\/p>\n<p><strong>Database:<\/strong><\/p>\n<ul>\n<li>pu\u00f2 aggiornare un attributo senza caricare l&#8217;intero oggetto in memoria<\/li>\n<li>\u00e8 lento nel creare nuovi record<\/li>\n<li>agisce su dati residenti sul disco rigido<\/li>\n<\/ul>\n<p><strong>Core Data:<\/strong><\/p>\n<ul>\n<li>tiene aggiornate le connessioni fra gli oggetti automaticamente<\/li>\n<li>quando un oggetto viene cancellato \u00e8 possibile cancellare automaticamente quelli che gli sono collegati (come vedremo in un prossimo tutorial)<\/li>\n<li>agisce su dati residenti in ram<\/li>\n<li>istanziare nuovi record \u00e8 rapido<\/li>\n<li>le modifiche agli oggetti sono osservabili con il <strong>Key-Value Observing<\/strong><\/li>\n<\/ul>\n<p><strong>Il compromesso<\/strong>:<\/p>\n<p>in Core Data istanziare gli oggetti \u00e8 rapido, perch\u00e9 sono in RAM piuttosto che sull&#8217;HD, ma per modificare anche un solo attributo o per cancellare un&#8217;oggetto \u00e8 necessario caricarlo prima in RAM.<br \/>\nQuindi, se vogliamo sviluppare un&#8217;app, in cui modifichiamo molto spesso poche propriet\u00e0 in pi\u00f9 migliaia di record (esempio: lettore rss, letto, non letto) allora SQLite sar\u00e0 pi\u00f9 rapido di Core Data.<\/p>\n<h4>2. Creiamo le nostre classi Model<\/h4>\n<p>Torniamo all&#8217;app che abbiamo sviluppato nella scorsa puntata.<br \/>\nFinora abbiamo usato <strong>setValue:forKey:<\/strong> per modificare e ottenere i valori delle propriet\u00e0 nelle istanze della nostra Entit\u00e0.<br \/>\nIl Key-Value Coding ci permette di accedere ad ogni propriet\u00e0, di qualunque classe, per cui \u00e8 disponibile un metodo <strong>setter<\/strong> e un metodo <strong>getter<\/strong>, che seguano questa naming convention:<br \/>\n<code><\/p>\n<dl>\n<dt>getter<\/dt>\n<dd><em>nomeVariabile<\/em> (quindi non <em>getNomeVariabile<\/em>, che viene usato in un'altro caso)<\/dd>\n<dt>setter<\/dt>\n<dd><em>setNomeVariabile<\/em> (sempre usando il <em>Camel Case<\/em>)<\/dd>\n<\/dl>\n<p><\/code><\/p>\n<p>Quindi \u00e8 una soluzione generica che funziona, ma che comporta un notevole spreco di caratteri, che scriviamo senza l&#8217;aiuto dell&#8217;autocompletamento di Xcode e soprattutto senza il <em>type checking<\/em>, per cui abbiamo una notevole gamma di errori possibili che non verranno segnalati al <em>compile-time<\/em>.<br \/>\nPer ovviare a questi inconvenienti possiamo creare una sottoclasse di <strong>NSManagedObject<\/strong> per la nostra Entit\u00e0.<br \/>\nC&#8217;\u00e8 un modo rapido di sottoclassare <strong>NSManagedObject<\/strong> avendo gi\u00e0 definito gli attributi dell&#8217;Entit\u00e0 nell&#8217;editor grafico di Core Data: apriamo il nostro <strong>xcdatamodel<\/strong> nell&#8217;editor e selezioniamo l&#8217;Entit\u00e0 per cui vogliamo creare una classe, nel nostro caso <strong>Contatto<\/strong>.<br \/>\nA questo punto scegliamo dal menu <strong>File<\/strong> > <strong>New File&#8230;<\/strong>, sotto <strong>Cocoa Touch Class<\/strong> avremo accesso ad un nuovo template: <strong>Managed Object Class<\/strong>.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig1-300x222.png\" alt=\"Selezioniamo l&#039;Entit\u00e0...\" title=\"CD2-fig1\" width=\"300\" height=\"222\" class=\"alignnone size-medium wp-image-5389\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig1-300x222.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig1-150x111.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig1.png 325w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig2-300x233.png\" alt=\"Scegliamo il template...\" title=\"CD2-fig2\" width=\"300\" height=\"233\" class=\"alignnone size-medium wp-image-5390\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig2-300x233.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig2-150x116.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig2.png 867w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Andiamo avanti nello wizard e assicuriamoci che <strong>Add To Project:<\/strong> punti al nostro progetto e che nei targets sia selezionato <strong>CoreDataPart2<\/strong>, e nella schermata successiva che l&#8217;Entit\u00e0 sia selezionata (\u00e8 possibile generare Classi per pi\u00f9 Entit\u00e0 contemporaneamente, se il nostro file xcdatamodel contenesse pi\u00f9 di un&#8217;Entit\u00e0 sarebbero tutte elencate qui), come anche <strong>Generate Accessors<\/strong> e <strong>Generate Obj-C 2.0 properties<\/strong> e poi confermiamo premendo Finish.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig3-300x233.png\" alt=\"Dentro il wizard - 1\" title=\"CD2-fig3\" width=\"300\" height=\"233\" class=\"alignnone size-medium wp-image-5391\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig3-300x233.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig3-150x116.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig3.png 867w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig4-300x233.png\" alt=\"Dentro il wizard - 2\" title=\"CD2-fig4\" width=\"300\" height=\"233\" class=\"alignnone size-medium wp-image-5392\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig4-300x233.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig4-150x116.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig4.png 867w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>A questo punto i file .h e .m della nostra classe sono stati aggiunti al progetto, e nel file xcdatamodel la classe della nostra Entit\u00e0, <strong>NSManagedObject<\/strong> \u00e8 stata sostituita con la nuova classe, <strong>Contatto<\/strong>. E necessario salvare il file xcdatamodel per finalizzare il cambiamento.<br \/>\nDiamo un&#8217;occhiata all&#8217;interfaccia della classe Contatto.<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n#import <CoreData\/CoreData.h>\r\n\r\n@interface Contatto :  NSManagedObject  \r\n{\r\n}\r\n\r\n@property (nonatomic, retain) NSString * nick;\r\n@property (nonatomic, retain) NSString * cognome;\r\n@property (nonatomic, retain) NSString * nome;\r\n\r\n@end\r\n<\/pre>\n<p>Vediamo che eredita da <strong>NSManagedObject<\/strong> e che anche se gli attributi dell&#8217;Entit\u00e0 non sono dichiarati come variabili d&#8217;istanza poi vengono comunque generate le propriet\u00e0.<br \/>\nPer capire questa particolarit\u00e0 dobbiamo vedere anche l&#8217;implementazione.<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n#import \"Contatto.h\"\r\n\r\n@implementation Contatto \r\n\r\n@dynamic nick;\r\n@dynamic cognome;\r\n@dynamic nome;\r\n\r\n@end\r\n<\/pre>\n<p>Le propriet\u00e0 non vengono sintetizzate usando la direttiva <strong>@syntesize<\/strong>, ma con la direttiva <strong>@dynamic<\/strong>, cio\u00e9 promettiamo al compilatore che saranno presenti al runtime, generate  e gestite da Core Data. Naturalmente se dovessero mancare a causa di errori di battitura o altro, l&#8217;app crasherebbe.<\/p>\n<h4>3. Aggiorniamo i metodi che utilizzano il KVC<\/h4>\n<p>Adesso che abbiamo la nostra classe <strong>Model<\/strong> dobbiamo rimaneggiare tutto il codice nell&#8217;applicazione dove abbiamo usato il <strong>KVC<\/strong>.<\/p>\n<p>Per prima cosa importiamo l&#8217;header in CoreDataPart2AppDelegate.m;<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n#import \"CoreDataPart2AppDelegate.h\"\r\n#import \"Contatto.h\"\r\n<\/pre>\n<p>e poi modifichiamo i metodi interessati: <strong>addContatto<\/strong>, <strong>cellForRowAtIndexPath<\/strong>.<\/p>\n<p><strong>addContatto<\/strong>:<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n\/\/Otteniamo il puntatore al NSManagedContext\r\nNSManagedObjectContext *context = [self managedObjectContext];\r\n\r\n\/\/Parte1: Creiamo un'istanza di NSManagedObject per l'Entit\u00e0 che ci interessa\r\n\/\/Parte2: Creiamo un'istanza della classe Model dell'Entit\u00e0 che ci interessa, usando comunque NSEntityDescription\r\nContatto *contatto = [NSEntityDescription\r\n                                   insertNewObjectForEntityForName:@\"Contatto\" \r\n                                   inManagedObjectContext:context];\r\n\t\t\r\n\/\/Parte1: Usando il Key-Value Coding inseriamo i dati presi dall'interfaccia nell'istanza dell'Entit\u00e0 appena creata\r\n\/\/Parte2: Inseriamo i dati usando le propriet\u00e0 della classe Contatto\r\ncontatto.cognome = surnameField.text;\r\ncontatto.nome = nameField.text;\r\ncontatto.nick = nickField.text;<\/pre>\n<p><strong>cellForRowAtIndexPath<\/strong>:<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n\/\/ Set up the cell...\r\n\t\r\n\/\/Parte1: istanziamo NSManagedObject perch\u00e9 gli oggetti dentro l'array sono di quel tipo\r\n\/\/Parte2: istanziamo invece Contatto\r\nContatto *contatto = [contattiList objectAtIndex:indexPath.row];\r\n\t\r\n\/\/Parte1: accediamo ai dati contenuti dal'oggetto utilizzando il Key-Value Coding\r\n\/\/Parte2: accediamo ai dati utilizzando le propriet\u00e0 della classe Contatto\r\ncell.textLabel.text = [NSString stringWithFormat:@\"%@ %@\", contatto.nome, contatto.cognome];\r\ncell.detailTextLabel.text = contatto.nick;\r\n\t\r\nreturn cell;\r\n<\/pre>\n<p>Et voil\u00e0, proviamo la nostra app e vediamo che funziona come prima, ma usando la classe Model che abbiamo generato.<\/p>\n<h4>4. Aggiungiamo altre funzionalit\u00e0: Modifica ed Elimina i record gi\u00e0 inseriti<\/h4>\n<p>Per prima cosa aggiungiamo al nostro file .h due variabili d&#8217;istanza, due metodi e un protocollo.<br \/>\nLe variabili d&#8217;istanza sono <strong>currentRecord<\/strong> e <strong>addButton<\/strong>, un&#8217;intero e un&#8217;outlet.<br \/>\nLa funzione di <strong>currentRecord<\/strong> \u00e8 tenere traccia su che record agiranno <strong>addContatto<\/strong> e <strong>deleteContatto<\/strong>, se abbiamo selezionato un record nella tabella sar\u00e0 uguale al suo <strong>indexPath.row<\/strong>, mentre quando non c&#8217;\u00e8 record selezionato sar\u00e0 uguale a -1.<br \/>\nLa funzione di <strong>addButton<\/strong> \u00e8 darci l&#8217;accesso al pulsante aggiungi, per cambiare il suo testo da <strong>&#8220;Aggiungi&#8221;<\/strong> in <strong>&#8220;Modifica&#8221;<\/strong> e viceversa.<br \/>\nIl protocollo da aggiungere a quelli supportati \u00e8 <strong>UITableViewDelegate<\/strong>, di cui useremo <strong>didSelectRowAtIndexPath:<\/strong>.<br \/>\nI metodi sono <strong>deleteContatto<\/strong> e <strong>clearFields<\/strong>. Dovremo pulire i campi in due metodi diversi: <strong>addContatto<\/strong> e <strong>deleteContatto<\/strong>, quindi \u00e8 meglio estrarre la funzionalit\u00e0 da addContatto ed inserirla in un metodo apposito: <strong>clearFields<\/strong>.<br \/>\nIn <strong>deleteContatto<\/strong>, com&#8217;\u00e8 facilmente deducibile dal nome, agiremo sul record selezionato in <strong>didSelectRowAtIndexPath:<\/strong> eliminandolo.<br \/>\n<strong>showContatti<\/strong> non verr\u00e0 pi\u00f9 invocato schiacciando il pulsante mostra, quindi sostituiamo <strong>IBAction<\/strong> con <strong>void<\/strong>.<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n#import <UIKit\/UIKit.h>\r\n#import <CoreData\/CoreData.h>\r\n\r\n@interface CoreDataPart2AppDelegate : NSObject <UIApplicationDelegate, UITableViewDataSource, UITableViewDelegate> {\r\n    \r\n    UIWindow *window;\r\n\t\r\n\tIBOutlet UITextField *nameField;\r\n\tIBOutlet UITextField *surnameField;\r\n\tIBOutlet UITextField *nickField;\r\n\tIBOutlet UITableView *contattiTable;\r\n\t\r\n\tIBOutlet UIButton *addButton;\r\n\tNSInteger currentRecord;\r\n\t\r\n\tNSArray *contattiList;\r\n    \r\n@private\r\n    NSManagedObjectContext *managedObjectContext_;\r\n    NSManagedObjectModel *managedObjectModel_;\r\n    NSPersistentStoreCoordinator *persistentStoreCoordinator_;\r\n}\r\n\r\n@property (nonatomic, retain) IBOutlet UIWindow *window;\r\n\r\n@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;\r\n@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;\r\n@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;\r\n\r\n- (NSString *)applicationDocumentsDirectory;\r\n\r\n- (void) showContatti;\r\n- (void) clearFields;\r\n- (IBAction) addContatto;\r\n- (IBAction)deleteContatto;\r\n\r\n@end\r\n<\/pre>\n<p>Apriamo <strong>MainWindow.xib<\/strong> e colleghiamo l&#8217;outlet per addButton.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig5.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig5.png\" alt=\"Colleghiamo l&#039;outlet per addButton.\" title=\"CD2-fig5\" width=\"287\" height=\"75\" class=\"alignnone size-full wp-image-5410\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig5.png 287w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/12\/CD2-fig5-150x39.png 150w\" sizes=\"auto, (max-width: 287px) 100vw, 287px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Adesso passiamo a <strong>CoreDataPart2AppDelegate.m<\/strong> e inseriamo i nuovi metodi, modificando quelli vecchi dove necessario.<br \/>\nPer prima cosa sostituiamo anche qui <strong>void<\/strong> ad <strong>IBAction<\/strong> per <strong>showContatti<\/strong>, poi aggiungiamo un&#8217;invocazione a <strong>showContatti<\/strong> in <strong>didFinishLaunchingWithOptions:<\/strong>, per mostrare eventuali record gi\u00e0 presenti all&#8217;avvio dell&#8217;app e settiamo <strong>currentRecord = -1<\/strong> come valore iniziale.<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n- (void) showContatti {\r\n\t\/\/Otteniamo il puntatore al NSManagedContext\r\n\tNSManagedObjectContext *context = [self managedObjectContext];\r\n\t\r\n\t\/\/istanziamo la classe NSFetchRequest di cui abbiamo parlato in precedenza\r\n\tNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];\r\n\t\r\n\t\/\/istanziamo l'Entit\u00e0 da passare alla Fetch Request\r\n\tNSEntityDescription *entity = [NSEntityDescription \r\n\t\t\t\t\t\t\t\t   entityForName:@\"Contatto\" inManagedObjectContext:context];\r\n\t\/\/Settiamo la propriet\u00e0 Entity della Fetch Request\r\n\t[fetchRequest setEntity:entity];\r\n\t\r\n\t\/\/Eseguiamo la Fetch Request e salviamo il risultato in un array, per visualizzarlo nella tabella\r\n\tNSError *error;\r\n\tNSArray *fo = [context executeFetchRequest:fetchRequest error:&error];\r\n\tcontattiList = [fo retain];\r\n\t\r\n\t[fetchRequest release];\r\n\t\r\n\t[contattiTable reloadData];\r\n}\r\n<\/pre>\n<pre lang=\"objc\" line=\"1\">\r\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    \r\n\t\r\n    \/\/ Override point for customization after application launch.\r\n\t\r\n    [window makeKeyAndVisible];\r\n\t\r\n\t\/\/aggiorniamo la tabella\r\n\t[self showContatti];\r\n\t\r\n\t\/\/settiamo il valore iniziale di currentRecord\r\n\tcurrentRecord = -1;\r\n\t\r\n\treturn YES;\r\n}\r\n<\/pre>\n<h4>5. Inseriamo i nuovi metodi<\/h4>\n<p>Estraiamo le righe che si occupano di pulire i campi da <strong>addContatto<\/strong> e inseriamole nel nuovo metodo <strong>clearFields<\/strong><\/p>\n<pre lang=\"objc\" line=\"1\">\r\n- (void)clearFields {\r\n\t\/\/per pulire i campi\r\n\tNSString *clear = [NSString stringWithFormat:@\"\"];\r\n\t\r\n\t[nameField setText:clear];\r\n\t[surnameField setText:clear];\r\n\t[nickField setText:clear];\r\n}\r\n<\/pre>\n<p>E&#8217; il momento di aggiungere i due metodi pi\u00f9 importanti di questa fase: <strong>deleteContatto<\/strong> e <strong>didSelectRowAtIndexPath:<\/strong><\/p>\n<pre lang=\"objc\" line=\"1\">\r\n- (IBAction)deleteContatto {\r\n\t\/\/Otteniamo il puntatore al NSManagedContext\r\n\tNSManagedObjectContext *context = [self managedObjectContext];\r\n\t\r\n\t\/\/usiamo currentRecord per agire sul record selezionato\r\n\t[context deleteObject:[contattiList objectAtIndex:currentRecord]];\r\n\t\r\n\t\/\/Effettuiamo il salvataggio gestendo eventuali errori\r\n\tNSError *error;\r\n\tif (![context save:&error]) {\r\n\t\tNSLog(@\"Errore durante il salvataggio: %@\", [error localizedDescription]);\r\n\t}\r\n\t\r\n\t\/\/resettiamo surrentRecord\r\n\tcurrentRecord = -1;\r\n\t\r\n\t\/\/puliamo i campi\r\n\t[self clearFields];\r\n\t\r\n\t\/\/aggiorniamo la tabella\r\n\t[self showContatti];\r\n}\r\n<\/pre>\n<p>Infine modifichiamo <strong>addContatto<\/strong> per fargli gestire sia il caso della modifica sia quello dell&#8217;aggiunta, pulire i campi col nuovo metodo, aggiornare la tabella e resettare <strong>currentRecord<\/strong>:<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n- (IBAction) addContatto {\r\n\t\/\/apriamo alertView se i campi non sono riempiti\r\n\tif (nameField.text.length == 0 || surnameField.text.length == 0 || nickField.text.length == 0) {\r\n\t\t\r\n\t\t\/\/Costruiamo l'alert che ci impedisce di inserire un record senza tutti i campi\r\n\t\tNSString *titolo = @\"Problema\";\r\n\t\tNSString *messaggio = @\"Devi inserire tutti i campi!\";\r\n\t\t\r\n\t\tUIAlertView *alert = [[UIAlertView alloc] initWithTitle:titolo\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmessage:messaggio\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t   delegate:self\r\n\t\t\t\t\t\t\t\t\t\t\t  cancelButtonTitle:@\"OK, non lo far\u00f2 pi\u00f9.\"\r\n\t\t\t\t\t\t\t\t\t\t\t  otherButtonTitles:nil];\r\n\t\t<div class=\"alert\"><button type=\"button\" class=\"close\">&#215;<\/button><div class=\"clear\"><\/div><\/div>;\r\n\t\t<div class=\"alert\"><button type=\"button\" class=\"close\">&#215;<\/button><div class=\"clear\"><\/div><\/div>;\r\n\t\t\r\n\t} else {\r\n\t\t\/\/per far sparire la tastiera\r\n\t\tif ([nameField isFirstResponder]) {\r\n\t\t\t[nameField resignFirstResponder];\r\n\t\t} else if ([surnameField isFirstResponder]) {\r\n\t\t\t[surnameField resignFirstResponder];\r\n\t\t} else if ([nickField isFirstResponder]){\r\n\t\t\t[nickField resignFirstResponder];\r\n\t\t}\r\n\t\t\r\n\t\t\/\/Otteniamo il puntatore al NSManagedContext\r\n\t\tNSManagedObjectContext *context = [self managedObjectContext];\r\n\t\t\r\n\t\t\/\/dichiariamo contatto senza istanziarlo, lo faremo all'interno dell'if.\r\n\t\tContatto *contatto;\r\n\t\t\r\n\t\t\/\/se \u00e8 selezionato un contatto agiremo su quello altrimenti ne aggiungeremo uno nuovo\r\n\t\tif (currentRecord >= 0) {\r\n\t\t\tcontatto =  [contattiList objectAtIndex:currentRecord];\r\n\t\t} else {\r\n\t\t\t\/\/Parte1: Creiamo un'istanza di NSManagedObject per l'Entit\u00e0 che ci interessa\r\n\t\t\t\/\/Parte2: Creiamo un'istanza della classe Model dell'Entit\u00e0 che ci interessa, usando comunque NSEntityDescription\r\n\t\t\tcontatto = [NSEntityDescription\r\n\t\t\t\t\t\t\t\t  insertNewObjectForEntityForName:@\"Contatto\" \r\n\t\t\t\t\t\t\t\t  inManagedObjectContext:context];\r\n\t\t}\r\n\t\t\t\t\r\n\t\t\/\/Parte1: Usando il Key-Value Coding inseriamo i dati presi dall'interfaccia nell'istanza dell'Entit\u00e0 appena creata\r\n\t\t\/\/Parte2: Inseriamo i dati usando le propriet\u00e0 della classe Contatto\r\n\t\tcontatto.cognome = surnameField.text;\r\n\t\tcontatto.nome = nameField.text;\r\n\t\tcontatto.nick = nickField.text;\r\n\t\t\r\n\t\t\/\/Effettuiamo il salvataggio gestendo eventuali errori\r\n\t\tNSError *error;\r\n\t\tif (![context save:&error]) {\r\n\t\t\tNSLog(@\"Errore durante il salvataggio: %@\", [error localizedDescription]);\r\n\t\t}\r\n\t\t\r\n\t\t\/\/puliamo i campi nell'interfaccia\r\n\t\t[self clearFields];\r\n\t\t\r\n\t\t\/\/aggiorniamo il testo del pulsante\r\n\t\t[addButton setTitle:@\"Aggiungi\" forState:UIControlStateNormal];\r\n\t}\r\n\t\r\n\t\/\/resettiamo currentRecord\r\n\tcurrentRecord = -1;\r\n\t\r\n\t\/\/aggiorniamo la tabella\r\n\t[self showContatti];\r\n\t\r\n}\r\n<\/pre>\n<h4>6. Tocchi finali<\/h4>\n<p>Per amor di evitare crash aggiungiamo un check in <strong>deleteContatto<\/strong>.<br \/>\nControlliamo che <strong>currentRecord<\/strong> sia maggiore o uguale a zero prima di cancellare l&#8217;oggetto.<\/p>\n<pre lang=\"objc\" line=\"1\">\r\n- (IBAction)deleteContatto {\r\n\tif (currentRecord >= 0) {\r\n\t\t\/\/Otteniamo il puntatore al NSManagedContext\r\n\t\tNSManagedObjectContext *context = [self managedObjectContext];\r\n\t\r\n\t\t\/\/usiamo currentRecord per agire sul record selezionato\r\n\t\t[context deleteObject:[contattiList objectAtIndex:currentRecord]];\r\n\t\r\n\t\t\/\/Effettuiamo il salvataggio gestendo eventuali errori\r\n\t\tNSError *error;\r\n\t\tif (![context save:&error]) {\r\n\t\t\tNSLog(@\"Errore durante il salvataggio: %@\", [error localizedDescription]);\r\n\t\t}\r\n\t\r\n\t\t\/\/resettiamo surrentRecord\r\n\t\tcurrentRecord = -1;\r\n\t\r\n\t\t\/\/puliamo i campi\r\n\t\t[self clearFields];\r\n\t\r\n\t\t\/\/aggiorniamo la tabella\r\n\t\t[self showContatti];\r\n\t}\r\n}<\/pre>\n<h4>7. Abbiamo finito<\/h4>\n<p>Adesso \u00e8 il momento di testare il programma, aggiungendo, modificando e cancellando record.<br \/>\nIl codice come al solito \u00e8 sul mio <a href=\"https:\/\/github.com\/doppioslash\/DevappTutorials\/tree\/master\/CoreDataPart2\" target=\"_blank\">github<\/a>.<\/p>\n<h4>Riassunto<\/h4>\n<p>Abbiamo elencato le differenze fra Core Data e i database, abbiamo creato una classe Model con la procedura automatica, l&#8217;abbiamo utilizzata nell&#8217;app, abbiamo aggiunto la possibilit\u00e0 di modificare e cancellare i record.<\/p>\n<h4>Nella prossima puntata<\/h4>\n<p>Come inserire dati da un semplice file txt a Core Data.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Eccoci alla seconda puntata della nostra Guida all&#8217;uso di Core Data nelle nostre applicazioni iPhone e iPad&#8230;.<\/p>\n","protected":false},"author":343,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[502,507,506,509,504,503,505,508,102,224],"class_list":["post-5380","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-core-data","tag-nsentitydescription","tag-nsfetchrequest","tag-nsmanagedobject","tag-nsmanagedobjectcontext","tag-nsmanagedobjectmodel","tag-nspersistentstorecoordinator","tag-nspredicate","tag-sqlite","tag-xml-iphone"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/5380","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/343"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=5380"}],"version-history":[{"count":91,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/5380\/revisions"}],"predecessor-version":[{"id":5521,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/5380\/revisions\/5521"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=5380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=5380"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=5380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}