J'utilise l'exemple de projet CoreDataBooks d'Apple comme outil d'apprentissage pour les données de base.
J'ai modifié l'application de sorte que lorsque l'application est chargée, je montre d'abord une page de menu, et non la table Table (RootViewController).
J'ai fait ce qui suit:
J'ai créé une page de menu dans le générateur d'interface (juste une vue avec un bouton)
CoreDataBooksAppDelegate.h ressemble maintenant à ceci:
// for the menu
@class MenuViewController;
@interface CoreDataBooksAppDelegate : NSObject <UIApplicationDelegate> {
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
UIWindow *window;
UINavigationController *navigationController;
//for the menu
MenuViewController *viewController;
}
- (IBAction)saveAction:sender;
//for the menu
@property (nonatomic, retain) IBOutlet MenuViewController *viewController;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, readonly) NSString *applicationDocumentsDirectory;
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@end
CoreDataBooksAppDelegate.m se présente comme suit:
#import "CoreDataBooksAppDelegate.h"
#import "RootViewController.h"
// for the menu
#import "MenuViewController.h"
@implementation CoreDataBooksAppDelegate
@synthesize window;
@synthesize navigationController;
// for the menu
@synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (void)applicationDidFinishLaunching:(UIApplication *)application {
RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
rootViewController.managedObjectContext = self.managedObjectContext;
// for the menu
[window addSubview:viewController.view];
// Configure and show the window
[window makeKeyAndVisible];
}
Le reste de CoreDataAppDelegete.m reste inchangé.
Dans le MenuViewController lorsque l'utilisateur clique sur le bouton, l'action suivante est exécutée:
RootViewController *modalViewController1 = [[[RootViewController alloc] initWithNibName:nil bundle:nil] autorelease];
[self presentModalViewController:modalViewController1 animated:YES];
Dans IB, j'ai modifié MainWindow.xib pour appeler MenuViewController plutôt que RootViewController.
Ainsi, l'application se charge et le menu s'affiche correctement avec le bouton. En cliquant sur le bouton, l'application se bloque à l'intérieur de viewDidLoad du RootViewController.
Il se bloque ici:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1 START viewDidLoad RootViewController");
self.title = @"Books";
// Set up the edit and add buttons.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
NSLog(@"2 setup button viewDidLoad RootViewController");
// Configure the add button.
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addBook)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
NSLog(@"3 viewDidLoad RootViewController");
NSError *error;
// HERE IS THE CRASH SITE
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Does not reach this point in viewDidLoad RootViewController");
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort(); // Fail
}
NSLog(@"END viewDidLoad RootViewController");
}
Dans la console, je reçois ce qui suit:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Book''
J'ai lu des informations sur cette exception, mais je ne connais pas les étapes appropriées pour la résoudre.
D'accord.
Placer le code suivant dans viewDidLoad du RootViewController élimine l'erreur:
if (managedObjectContext == nil)
{
managedObjectContext = [(CoreDataBooksAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(@"After managedObjectContext: %@", managedObjectContext);
}
J'ai trouvé quelqu'un avec un problème similaire ici sur SO: link text
Comme Aryeh l'a souligné dans cet article: "En résumé, vous essayez d'extraire une entité d'un objet objectContext qui n'a pas encore été configuré. Vous avez donc la possibilité de la configurer à ce moment ou de le faire ailleurs dans l'application avant le chargement de cette vue . "
Dans applicationDidFinishLaunching: vous procédez comme suit:
rootViewController.managedObjectContext = self.managedObjectContext;
Mais je ne vois pas le code où self.managedObjectContext est installé. applicationDidFinishLaunching est appelé assez tôt. Êtes-vous sûr de configurer le contexte de l'objet géré?
Avez-vous changé le modèle de données de base? Cette erreur est courante lorsque le modèle Core Data d'une application change sans modifier également la base de données SQLite sous-jacente. Les données stockées et le modèle ne sont donc pas synchronisés.
Essayez de supprimer complètement votre application du simulateur ou du périphérique de test, puis de la réinstaller et de réessayer.
Au cours de mon développement, je n'ai pas pu trouver d'entités que j'ai ajoutées plus tard. Ce qui a fonctionné pour moi: (fondamentalement un conseil de santé mentale :-)
Désinstallez l'application CHAQUE FOIS que vous modifiez le modèle de données!
Le modèle de données est mis en cache par Core Data entre les installations pour garantir le maintien de l'intégrité. Supprimez l'application du simulateur/iPhone pour pouvoir tester vos modifications.
PS: est-ce que quelqu'un sait comment faire ça automatiquement?