2012-12-27 4 views
9

La maggior parte (tutto quello che ho visto) tutorial Core Data utilizzare il seguente frammento di codice con @"MyEntityClass" hard-coded in:NSStringFromClass ([Classe MyEntityClass]) genera un nome di Entità dei dati di base sicuro?

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"MyEntityClass"]; 

E 'sicuro usare NSStringFromClass() come un nome di entità?

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([MyEntityClass class])]; 

Questo cuciture ad essere molto easer da affrontare per quanto riguarda il refactoring e simili. Soprattutto perché sto creando Xcode per creare le sottoclassi NSManagedObject. Chiedo perché non l'ho mai visto prima, quindi forse mi manca qualcosa.

risposta

14

Sì, quel codice va bene, se la classe dell'entità è impostata su MyEntityClass nel modello.

preferisco dare alla classe di entità un metodo di classe che restituisce il nome dell'entità:

+ (NSString *)entityName { 
    return NSStringFromClass(self); 
} 

e chiamare in questo modo:

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:[MyEntityClass entityName]]; 

In questo modo, se voglio cambiare la classe nome senza modificare il nome dell'entità nel modello, posso semplicemente apportare la modifica al metodo di classe:

+ (NSString *)entityName { 
    return @"NewEntityName"; 
} 

Perché dovrei farlo? Bene, potrei decidere un nome migliore per l'entità. La modifica del nome della classe non interrompe la compatibilità con un archivio persistente dei dati principali esistente, ma cambia il nome dell'entità nel file del modello. Posso cambiare il nome della classe e il metodo entityName, ma lasciare il nome dell'entità invariato nel modello, e quindi non devo preoccuparmi della migrazione. (La migrazione leggera supporta le entità ridenominate, quindi non è un grosso problema in ogni caso.)

Si può andare oltre ed effettivamente il metodo entityName cercare il nome dell'entità dal modello a oggetti gestito in fase di esecuzione. Supponiamo che il vostro delegato applicazione ha un messaggio che restituisce il modello oggetto gestito:

+ (NSString *)entityName { 
    static NSString *name; 
    static dispatch_once_t once; 
    dispatch_once(&once, ^{ 
     NSString *myName = NSStringFromClass(self); 
     NSManagedObjectModel *model = [(AppDelegate *)[UIApplication delegate] managedObjectModel]; 
     for (NSEntityDescription *description in model.entities) { 
      if ([description.managedObjectClassName isEqualToString:myName]) { 
       name = description.name; 
       break; 
      } 
     } 
     [NSException raise:NSInvalidArgumentException 
      format:@"no entity found that uses %@ as its class", myName]; 
    }); 
    return name; 
} 

Ovviamente, se si vuole veramente fare questo, si dovrebbe scomporre il contenuto del blocco dispatch_once in un metodo di supporto, probabilmente la vostra applicazione delegato (o ovunque tu abbia il modello).

+0

Se non si desidera andare oltre al codice di ricerca aggiuntivo, è possibile aggiungere questo asser prima di qualsiasi accesso interno a 'entityName:'. 'NSAssert (context.persistentStoreCoordinator.managedObjectModel.entitiesByName [[self entityName]]! = Nil, @" Entità con nome% @ non trovata nel modello. Il nome della tua classe è uguale al nome della tua entità? ", [Self entityName ]); 'Questo emetterà un errore in fase di esecuzione se il nome dell'entità del modello non corrisponde al nome della classe. –

+0

in questo caso devi aggiungere il codice alla categoria di ogni oggetto generato automaticamente? solo preoccupato di creare un nuovo file per le classi per aggiungere solo questa funzione. –

+0

@VitaliK Puoi aggiungere una categoria a 'NSManagedObject', ma se lo fai, non chiamarlo' entityName' perché è troppo generico. Utilizza un prefisso, ad esempio "Vitali_entityName" per evitare conflitti di nome. –