iphone,将数据保存在多对多关系中,核心数据

时间:2010-11-26 03:51:52

标签: iphone core-data entity-relationship save one-to-many

我正在使用Core Data开发一个小型iphone应用程序,在那里我有一个Person和一个Image实体。人与形象之间的关系是多方面的。一个人到多个图像。

保存方法出现问题。在首次保存期间,我需要'添加'多个图像数据,我从ImagePickerViewController到Person,然后'保存'Person实体到实际DB。 ((以相同的方法))

if (managedObjectContext == nil)
{
managedObjectContext = [(CoreDataCombine01AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
//???: how to init _PersonImage?
_PersonImage = (PersonImage *)[NSEntityDescription insertNewObjectForEntityForName:@"PersonImage" inManagedObjectContext:managedObjectContext];     
//_PersonImage = [_PersonImage init];
//_PersonImage = [[_PersonImage alloc] init];
_PersonImage.originalImage = imageData;

managedObjectContext = nil;
[managedObjectContext release];

 if (managedObjectContext == nil)
  {
  managedObjectContext = [(CoreDataCombine01AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
person = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:managedObjectContext]; 
[person addPersonToPersonImageObject:_PersonImage];//runTime error 
[_PersonImage release];

NSError *error = nil;
if (![person.managedObjectContext save:&error]) {
    // Handle error
    NSLog(@"Unresolved error at save %@, %@", error, [error userInfo]);
    exit(-1);  // Fail
}

然后我得到错误说:

"-[NSConcreteMutableData CGImage]: unrecognized selector sent to instance" 

 "*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMutableData CGImage]: unrecognized selector sent to instance".

我猜这个错误来自从一个managedObjectContext 中双重使用NSEntityDescription。所以我只是初始化Person类,它自动从数据模型派生并手动导入,就像注释行而不是使用managedObjectContext。

它没有给出任何错误,但是当我点击我的保存按钮时给我运行时错误。

当我使用一对一的关系时,保存没有问题所以我想使用Person的managedObjectContext是正确的方法。但是,一旦我使用to-many关系,我需要将Image数据保存到PersonImage实体。并且实体必须以某种方式初始化。

我错过了什么?

2 个答案:

答案 0 :(得分:4)

好的。

我已经看过你在GitHub上发布的代码,发现你的DetailView控制器存在一些问题,我将在下面概述。

首先,您没有正确地将托管对象上下文传递给详细信息视图,这意味着当您尝试保存对象时,没有任何上下文可以保存它们。将托管对象上下文视为持久性存储的“草稿”。您对NSManagedObject所做的任何更改都将被跟踪并保留在您的上下文中,直到您使用[managedObjectContext save]命令保留它们。

所以,为了清楚起见,您正在AppDelegate中创建上下文,然后使用rootViewController.managedObjectContext = self.managedObjectContext

将对它的引用传递给RootViewController

从RootViewController,您需要使用相同的技术将managedObjectContext传递给DetailView。因此,在tableView:didSelectRowAtIndexPath:方法中,您应该传递对上下文的引用,以便跟踪您在该视图上所做的任何更改,并最终可以保留这些更改:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {    
     DetailView *detailView = [[DetailView alloc] initWithNibName:@"DetailView" bundle:nil];
     detailView.event = (Event *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
     detailView.managedObjectContext = self.managedObjectContext;

     // ...
     [self.navigationController pushViewController:detailView animated:YES];
     [detailView release];
}

我还更新了对managedObjectContext的所有其他引用,您在其中实例化一个新的上下文对象,只是指向self.managedObjectContext,即:

JustString *_justString = [NSEntityDescription insertNewObjectForEntityForName:@"JustString" inManagedObjectContext:self.managedObjectContext];

一旦这样做了,只有一件事阻止你正确保存图像对象,这是TechZen在上面提到的。

在DetailView控制器中,您有一个imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{方法,您可以将UIImage转换为NSData,然后将其分配给Image实体实例。

问题在于你的对象模型中已经有一个名为-(id)transformedValue:(id)value的变换器方法(参见Event.m)。

所以基本上你试图将UIImage转换为NSData,然后将NSData传递给实体,实际上它正在期待UIImage。在这种情况下,我建议您让对象模型处理数据转换,以便在DetailView控制器中注释掉UIImage到NSData转换器代码,并将图像直接传递给托管对象:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    UIImage *selectedImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
    // Transform the image to NSData
    // ImageToDataTransformer *transformer = [[[ImageToDataTransformer alloc] init] autorelease];
    // NSData *imageData = [transformer transformedValue:selectedImage];
    Image *_image = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:self.managedObjectContext];    
    _image.justImage = selectedImage;
    [event addEventToImageObject:_image];
    [picker dismissModalViewControllerAnimated:YES];
}

在那之后,你应该好好去尝试一下,让我们知道它是否能解决你的问题。

CoreData可能会有一些陡峭的学习曲线,但一旦你“了解它”,你就会发现它是iOS开发中最精美的API之一。

祝你好运,让我们知道你怎么走! ROG

答案 1 :(得分:1)

您获得的错误消息是由于您为UIImage实例混淆NSData实例而引起的。

与NSString,NSArray和类似的核心类一样,NSData是一个类集群而不是单个类。 NSConcreteMutableData是集群中的一个类。

您的问题出现是因为您尝试将消息CGImage发送到NSData实例,当然该消息没有CGImage方法。

由于您必须使用值转换器将图像存储在Core Data属性中,我建议您查看值变换器和/或分配图像的方法。

查看您的代码,我怀疑您将Person.originalImage设置为可转换属性,但您尝试为其分配NSData对象。当值转换器尝试转换NSData实例时,它认为它是UIImage,它会生成错误。