Core Data 应用程序不会从持久存储中加载数据

Posted

技术标签:

【中文标题】Core Data 应用程序不会从持久存储中加载数据【英文标题】:Core Data app don't load data from persistent store 【发布时间】:2010-07-19 17:15:43 【问题描述】:

我正在开发的应用程序有任何问题... 我正在使用 Core Data,我只是编写初始代码... 但我的问题之一是:Core Data 不会加载存储在持久存储中的数据... 这是我的代码!

MyWishesAppDelegate.h


#import UIKit/UIKit.h
#import CoreData/CoreData.h

@interface MyWishesAppDelegate : NSObject  

    UIWindow *window;
 UITabBarController *tabBarController;

@private
    NSManagedObjectContext *managedObjectContext_;
    NSManagedObjectModel *managedObjectModel_;
    NSPersistentStoreCoordinator *persistentStoreCoordinator_;


@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;

@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (NSString *)applicationDocumentsDirectory;

@end

MyWishesAppDelegate.m


#import "MyWishesAppDelegate.h"


@implementation MyWishesAppDelegate

@synthesize window;
@synthesize tabBarController;


#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     

    // Override point for customization after application launch.
 [window insertSubview:tabBarController.view atIndex:0];
    [window makeKeyAndVisible];

 return YES;



- (void)applicationWillResignActive:(UIApplication *)application 
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions
  (such as an incoming phone call or SMS message)
  or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */



- (void)applicationDidEnterBackground:(UIApplication *)application 
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application
  to its current state in case it is terminated later. 
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
     */



- (void)applicationWillEnterForeground:(UIApplication *)application 
    /*
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
     */



- (void)applicationDidBecomeActive:(UIApplication *)application 
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background,
  optionally refresh the user interface.
     */



- (void)applicationWillTerminate:(UIApplication *)application 

    NSError *error = nil;
    if (managedObjectContext_ != nil) 
        if ([managedObjectContext_ hasChanges] && ![managedObjectContext_ save:&error]) 

            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
         
    



#pragma mark -
#pragma mark Core Data stack


- (NSManagedObjectContext *)managedObjectContext 

    if (managedObjectContext_ != nil) 
        return managedObjectContext_;
    

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) 
        managedObjectContext_ = [[NSManagedObjectContext alloc] init];
        [managedObjectContext_ setPersistentStoreCoordinator:coordinator];
    
    return managedObjectContext_;



- (NSManagedObjectModel *)managedObjectModel 

    if (managedObjectModel_ != nil) 
        return managedObjectModel_;
    
    NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"MyWishes" ofType:@"momd"];
    NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
    managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 

    return managedObjectModel_;



- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 

    if (persistentStoreCoordinator_ != nil) 
        return persistentStoreCoordinator_;
    

    NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"MyWishes.sqlite"]];

    NSError *error = nil;
    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) 

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
        

    return persistentStoreCoordinator_;



#pragma mark -
#pragma mark Application's Documents directory

- (NSString *)applicationDocumentsDirectory 
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];



#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application 



- (void)dealloc 

    [managedObjectContext_ release];
    [managedObjectModel_ release];
    [persistentStoreCoordinator_ release];

 [tabBarController release];
    [window release];
    [super dealloc];



@end

WishlistViewController.h


#import UIKit/UIKit.h
#import CoreData/CoreData.h

@interface WishlistViewController : UITableViewController  

@private
 NSFetchedResultsController *_fetchedResultsController;



@property (nonatomic, readonly) NSFetchedResultsController *fetchedResultsController;

-(void)add;
-(IBAction)edit;

@end

WishlistViewController.m


#import "WishlistViewController.h"
#import "MyWishesAppDelegate.h"

@implementation WishlistViewController

@synthesize fetchedResultsController = _fetchedResultsController;

#pragma mark -
#pragma mark Actions

-(void)add 
 NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
 NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
 NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

 NSError *error;
 if (![context save:&error])
  NSLog(@"Error saving entity: %@", [error localizedDescription]);

 // TODO: instantiate detail editing controller and push onto stack


-(IBAction)edit 
 BOOL editing = !self.tableView.editing;
 self.navigationItem.rightBarButtonItem.enabled = !editing;
 self.navigationItem.leftBarButtonItem.title = (editing) ? (@"Done") : (@"Edit");
 [self.tableView setEditing:editing animated:YES];


#pragma mark -
#pragma mark View lifecycle

-(void)viewDidLoad 
 [super viewDidLoad];
 NSError *error = nil;
 if (![[self fetchedResultsController] performFetch:&error]) 
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Errore caricamento dati"
              message:[NSString stringWithFormat:@"L'errore è stato: %@", [error localizedDescription]]
                delegate:self
             cancelButtonTitle:@"Ok!"
             otherButtonTitles:nil];
  [alert show];
 


-(void)viewDidAppear:(BOOL)animated 
 UIBarButtonItem *editButton = self.editButtonItem;
 [editButton setTarget:self];
 [editButton setAction:@selector(edit)];
 self.navigationItem.leftBarButtonItem = editButton;

 UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
                      target:self
                      action:@selector(add)];
 self.navigationItem.rightBarButtonItem = addButton;
 [addButton release];


#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];


- (void)viewDidUnload 


- (void)dealloc 
 [_fetchedResultsController release];
    [super dealloc];


#pragma mark -
#pragma mark Table View Methods

-(NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView 
 NSUInteger count = [[self.fetchedResultsController sections] count];
 if (count == 0) 
  count = 1;
 
 return count;


-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
 NSArray *sections = [self.fetchedResultsController sections];
 NSUInteger count = 0;
 if ([sections count]) 
  id  sectionInfo = [sections objectAtIndex:section];
  count = [sectionInfo numberOfObjects];
 
 return count;


-(UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

 static NSString *WishlistTableViewCell = @"WishlistTableViewCell";

 UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:WishlistTableViewCell];
 if (cell == nil) 
  cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:WishlistTableViewCell] autorelease];
 

 NSManagedObject *oneWish = [self.fetchedResultsController objectAtIndexPath:indexPath];
 cell.textLabel.text = [oneWish valueForKey:@"nome"];

 /*UIImageView *cellBg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cellBg.png"]];
 cell.backgroundView = cellBg;*/
 /*cell.detailTextLabel.text = [oneWish valueForKey:@"costo"];*/

 return cell;


-(void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
 // TODO: instantiate detail editing view controller and push onto stack


-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 

 if (editingStyle == UITableViewCellEditingStyleDelete) 
  NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
  [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

  NSError *error;
  if (![context save:&error]) 
   NSLog(@"Errore non risolto: %@, %@", error, [error userInfo]);
   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Errore salvataggio dati"
               message:@"Impossibile salvare dopo aver cancellato un elemento"
                 delegate:self
              cancelButtonTitle:@"Ok!"
              otherButtonTitles:nil];
   [alert show];
  
 


#pragma mark -
#pragma mark Fetched Results Controller

-(NSFetchedResultsController *)fetchedResultsController 

 if (_fetchedResultsController != nil) 
  return _fetchedResultsController;
 

 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 MyWishesAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
 NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;

 NSEntityDescription *entity = [NSEntityDescription entityForName:@"Wish" inManagedObjectContext:managedObjectContext];

 NSString *sectionKey = nil;
 NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:@"nome" ascending:YES];
 NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortByName, nil];
 [fetchRequest setSortDescriptors:sortDescriptors];
 [sortByName release];
 [sortDescriptors release];
 sectionKey = @"nome";

 [fetchRequest setEntity:entity];
 [fetchRequest setFetchBatchSize:20];

 NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                    managedObjectContext:managedObjectContext
                   sectionNameKeyPath:sectionKey
                      cacheName:@"Wish"];
 frc.delegate = self;
 _fetchedResultsController = frc;
 [fetchRequest release];

 return _fetchedResultsController;


-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
 [self.tableView beginUpdates];


-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
 [self.tableView endUpdates];


-(void)controller:(NSFetchedResultsController *)controller
  didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath
 forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath 

 switch(type) 
  case NSFetchedResultsChangeInsert:
   [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
   break;
  case NSFetchedResultsChangeDelete:
   [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
   break;
  case NSFetchedResultsChangeUpdate: 
   NSString *sectionKeyPath = [controller sectionNameKeyPath];
   if (sectionKeyPath == nil)
    break;
   NSManagedObject *changedObject = [controller objectAtIndexPath:indexPath];
   NSArray *keyParts = [sectionKeyPath componentsSeparatedByString:@"."];
   id currentKeyValue = [changedObject valueForKeyPath:sectionKeyPath];
   for (int i = 0; i )sectionInfo
    atIndex:(NSUInteger)sectionIndex
 forChangeType:(NSFetchedResultsChangeType)type 

 switch(type) 
  case NSFetchedResultsChangeInsert:
   if (!(sectionIndex == 0 && [self.tableView numberOfSections] == 1) && [self.tableView numberOfRowsInSection:0] == 0)
    [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
   break;
  case NSFetchedResultsChangeDelete:
   if (!(sectionIndex == 0 && [self.tableView numberOfSections] == 1) && [self.tableView numberOfRowsInSection:0] == 0)
    [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
   break;
  case NSFetchedResultsChangeMove:
   break;
  case NSFetchedResultsChangeUpdate:
   break;
  default:
   break;
 


#pragma mark -
#pragma mark Alert View Delegate

-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 
 exit(-1);



@end

有人可以帮助我吗?如果这段代码还有其他问题,可以跟我说……

【问题讨论】:

您需要更好地描述实际问题。 “核心数据不会加载存储在持久存储中的数据”并没有告诉我们太多。你有任何错误吗?你在表中看到了什么?您可以将数据写入存储而不出错吗?等等…… 究竟是什么不起作用? (您收到哪个错误消息?)--或者-- 您预期会发生什么?发生了什么? 不幸的是我没有收到错误...但是我在模拟器中启动我的应用程序并单击 con 添加按钮以在表中添加一行...添加了行但是如果我完全关闭我的应用程序,如果我重新启动它,我在表格视图中什么也看不到... 更新:我刚刚在模拟器和编辑模式下尝试了我的应用程序,如果我尝试删除一行,会出现一个弹出窗口告诉我无法保存...有没有存储过程有问题? 您的商店的路径是什么?您不能写入 mainBundle 目录。 【参考方案1】:

首先在调试器中运行,并在objc_exception_throw 上设置一个断点,这将导致您的应用在崩溃之前停止,这样您就可以看到有问题的代码行是什么。这将告诉您是什么导致了问题。

【讨论】:

【参考方案2】:

检查返回的值

#pragma mark Application's Documents directory

- (NSString *)applicationDocumentsDirectory 
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
 

我认为应该是这样的:

- (NSString *)applicationDocumentsDirectory 
    return [(NSArray *)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
 

【讨论】:

-lastObject 只会导致返回一个 nil,这应该在启动时给他一个错误。

以上是关于Core Data 应用程序不会从持久存储中加载数据的主要内容,如果未能解决你的问题,请参考以下文章

如何观察 Core Data 持久存储在包含应用程序和扩展程序之间的变化

应用重新启动时数据不会在 Core Data 中持久化

如何在 Core Data(例如 NSRect)中存储非标准的持久属性?

Core-Data:想要将新的 web xml 内容持久保存到我的数据存储中,而不是替换现有的

Core Data:为啥要创建自定义持久存储?

Core Data - 无法在 iOS 5.1 上创建持久存储