iphone, 以多对多关系保存数据, 核心数据

Posted

技术标签:

【中文标题】iphone, 以多对多关系保存数据, 核心数据【英文标题】:iphone, Saving data in to-many relationship, Core Data 【发布时间】:2010-11-26 03:51:52 【问题描述】:

我正在使用 Core Data 开发一个小型 iphone 应用程序,其中我有一个 Person 和一个 Image 实体。 Person 和 Image 之间的关系是对多的。一个人对许多图像。

问题发生在保存方法。在首先保存期间,我需要从 ImagePickerViewController 获得的多个图像数据“添加”到 Person,然后将 Person 实体“保存”到实际数据库。 ((用同样的方法))

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 是正确的方法。但是,一旦我使用多对多关系,我需要将图像数据保存到 PersonImage 实体。并且必须以某种方式初始化实体。

我错过了什么?

【问题讨论】:

【参考方案1】:

好的。

我查看了您在 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 实体实例。

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

所以基本上你试图将 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 之一。

祝你好运,让我们知道你的进展! 罗格

【讨论】:

嗨,罗格,在我根据您的建议处理之前有 2 个问题。 Q1) 是 _PersonImage.originalImage = imageData;与 [personImage setValue:imageData forKey:@"originalImage"];? Q2) 我们不使用 add'relationshipName'Object 方法吗?多对多关系免费提供的方法。 您好! Q1 - 正确,前提是您为 PersonImage 对象声明了 @property。我个人的偏好是 setValue:forKey。 Q2 - 不熟悉该方法,但我想它们必须是可以互换的。 我申请了 '[person setValue:personImage forKey:@"nameOfYourPersonToImageRelationShipHere"] ' 并且 Xcode 给我错误提示 "*** Terminating app due to unaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of一对多关系的值:属性 =“PersonToPersonImage”;所需类型 = NSSet;给定类型 = PersonImage;值 = (实体:PersonImage;id:0xec07c30 ; data: PersonImageToPerson = nil;" ///// 所以我猜我们使用 addPersonToPersonImageObject. 你试过我的建议了吗?我需要查看更多您的代码,可能是 Person 和 PersonImage 的 NSManagedObject 接口。 NSManagedObject 接口是指数据模型?我用屏幕截图更新了我的问题。【参考方案2】:

您收到的错误消息是由于您混淆了 UIImage 实例的 NSData 实例。

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

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

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

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

【讨论】:

感谢 TechZen。你是对的。问题出在滥用变压器方法。

以上是关于iphone, 以多对多关系保存数据, 核心数据的主要内容,如果未能解决你的问题,请参考以下文章

通过链接到SQL Server数据库的MS Access以多对多关系插入数据(中间表)

Swift核心数据多对多关系不保存实体

在 MS Access 中,如何以多对多关系列出记录,以使所列出的表中的记录不重复?

为核心数据手动创建多对多关系中的中间表

如何创建如何在 typeorm 中创建多对多关系,[NestJS]

以多对多关系对相关集进行排序