保存到 Coredata 崩溃

Posted

技术标签:

【中文标题】保存到 Coredata 崩溃【英文标题】:Saving to Coredata Crashing 【发布时间】:2015-02-04 16:05:39 【问题描述】:

我有 2 个类,PhotoCollectionviewController 和 AddPhotoViewController。 PhotoCollectionviewController 是 FetchResultViewController 的子类。当 AddPhotoViewController 首次出现在 navigationController 中并且我选择 PhotoCollectionviewController 时,我能够从库/相机('AddPhotoViewController')中选择一张照片。我已经交换了 segues,所以 PhotoCollectionviewController 是第一个 VC,但我现在遇到了一个错误。

CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。这通常是 NSManagedObjectContextObjectsDidChangeNotification 观察者中的一个错误。 -[__NSCFData compare:]: 无法识别的选择器使用 userInfo (null) 发送到实例 0x7fa5b2d78480

PhotoCollectionViewController.h

    #import "FetchResultViewController.h"
    #import "PhotoCell.h"
    #import "ViewController.h"
    #import "AppDelegate.h"


@interface PhotoCollectionViewController : FetchResultViewController <UICollectionViewDelegate, UICollectionViewDelegateFlowLayout,UIGestureRecognizerDelegate,UICollectionViewDataSource>

@property (strong, nonatomic) NSMutableArray *photoArray;

@property (strong, nonatomic) IBOutlet UICollectionView *photoDiaryCollectionView;

@end

PhotoCollectionViewController.m

#import "PhotoCollectionViewController.h"
#import "Photo.h"

@interface PhotoCollectionViewController ()

@end

@implementation PhotoCollectionViewController

@synthesize fetchResultsController = _fetchResultsController;

- (void)viewDidLoad

    [super viewDidLoad];

    self.photoArray =[[NSMutableArray alloc]init];


    self.photoDiaryCollectionView.delegate = self;
    self.photoDiaryCollectionView.dataSource = self;

    [NSFetchedResultsController deleteCacheWithName:@"Photos"];

    [self.fetchResultsController performFetch:nil];

    [self.photoDiaryCollectionView reloadData];

 //   [self getAllPhotos];


-(void)getAllPhotos

    for (Photo *aPhoto in self.fetchResultsController.fetchedObjects)

    
          UIImage *image = [UIImage imageWithData:aPhoto.photoData];

        [self.photoArray  addObject:image];
    


-(void) viewDidAppear:(BOOL)animated

    [self.photoDiaryCollectionView reloadData];


- (NSFetchedResultsController*)fetchResultsController


    if (_fetchResultsController == nil)

    
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
        NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"photoData" ascending:YES];
        [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
        fetchRequest.sortDescriptors = @[sort];

        _fetchResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.appDelegate.managedObjectContext sectionNameKeyPath:nil
                                                                                cacheName:@"Photos"];
        _fetchResultsController.delegate = self;
    

    return _fetchResultsController;


- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];


-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView

    return 1;



- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

    return self.fetchResultsController.fetchedObjects.count;


- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

    PhotoCell *cell = (PhotoCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"PhotoCell" forIndexPath:indexPath];

    Photo *photo = [self.fetchResultsController objectAtIndexPath:indexPath];

    UIImage *image = [UIImage imageWithData:photo.photoData];

    [self.photoArray  addObject:[UIImage imageWithData:photo.photoData]];

    [cell loadCell:image];

    return cell;


- (CGFloat) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section

    return 4;


- (CGFloat) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section

    return 1;


- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath





/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.

*/

@end

AddPhotoViewController.h

    #import "ViewController.h"
    #import "Photo.h"
    #import "AppDelegate.h"

@interface AddPhotoViewController : ViewController

@property (strong, nonatomic) IBOutlet UIImageView *photoImageView;

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;

- (IBAction)saveButtonPressed:(id)sender;

- (IBAction)takePhotoButtonPressed:(id)sender;
- (IBAction)pickFromLibraryButtonPressed:(id)sender;

@end

AddPhotoViewController.m

#import "AddPhotoViewController.h"

@interface AddPhotoViewController ()

@property (nonatomic,strong) UIImage *currentImage;

@end

@implementation AddPhotoViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view.


- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


-(void)saveImage

    AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    _managedObjectContext = [delegate managedObjectContext];

    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Photo"
                                                         inManagedObjectContext:self.managedObjectContext];

    Photo *photos  = (Photo*)[[NSManagedObject alloc]initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext];


    NSData *imageData = UIImagePNGRepresentation(self.currentImage);

    photos.photoData = imageData;

    //    [photos setPhotoData:imageData];

    [delegate saveContext];



-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 

      self.currentImage = [info objectForKey:UIImagePickerControllerOriginalImage];

    [picker dismissViewControllerAnimated:YES completion:Nil];

    self.photoImageView.image = self.currentImage;




- (IBAction)saveButtonPressed:(id)sender

    [self saveImage];
//    [self performSegueWithIdentifier:@"ImageSaved" sender:self];



- (IBAction)takePhotoButtonPressed:(id)sender

    if (([UIImagePickerController isSourceTypeAvailable:
          UIImagePickerControllerSourceTypeCamera] == NO))
        return;

    UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
    mediaUI.sourceType = UIImagePickerControllerSourceTypeCamera;
    mediaUI.allowsEditing = NO;
    mediaUI.delegate = self;

    [self presentViewController:mediaUI animated:YES completion:nil];



- (IBAction)pickFromLibraryButtonPressed:(id)sender

    if (([UIImagePickerController isSourceTypeAvailable:
          UIImagePickerControllerSourceTypePhotoLibrary] == NO))
        return;

    UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
    mediaUI.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    mediaUI.allowsEditing = NO;
    mediaUI.delegate = self;
    [self presentViewController:mediaUI animated:YES completion:nil];

@end

我真的不明白为什么这不起作用,除了导航控制器中 VC 的位置外,我什么都没改变

【问题讨论】:

尝试在你的项目中添加一个异常断点,这样你就可以准确地看到这个错误是从哪里来的 它在 [delegate saveContext] 处中断;在 -(void)saveImage 试试 [_managedObjectContext save:&error] 【参考方案1】:

我的猜测是你在某处有一个 NSManagedObjectContextObjectsDidChangeNotification 并且当它的目标被释放时你没有正确删除观察者,所以当通知到达时,观察者尝试在已经存在的前一个目标的地址上使用通知新对象,这就是它显示无法识别的选择器消息的原因

【讨论】:

以上是关于保存到 Coredata 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

如何在保存时调试 CoreData 崩溃?

从 coreData 加载图像时崩溃

具有自动保存功能的 CoreData 第一次保存,然后在所有后续自动保存中以“NoSuchFileError”崩溃

尝试在块中保存对象时崩溃。 (CoreData 无法满足...的错误)

iPhone - 在删除 CoreData 中的对象后尝试保存新对象时应用程序崩溃

CoreData MagicalRecord 保存方法在 iPhone5 上崩溃