保存到 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 第一次保存,然后在所有后续自动保存中以“NoSuchFileError”崩溃
尝试在块中保存对象时崩溃。 (CoreData 无法满足...的错误)