【问题标题】:iphone, Saving data in to-many relationship, Core Dataiphone, 以多对多关系保存数据, 核心数据
【发布时间】: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 实体。并且必须以某种方式初始化实体。

我错过了什么?

【问题讨论】:

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


    【解决方案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。你是对的。问题出在滥用变压器方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2016-09-08
    • 1970-01-01
    相关资源
    最近更新 更多