76

我是 iOS 新手。我一直在尝试制作一个应用程序,将从相机捕获的图像存储到CoreData. 我现在知道如何存储NSStringsNSDate和其他类型的数据,但很难存储图像。我读过很多文章说你必须将它写入磁盘并写入文件,但我似乎无法理解。

以下代码是我用来将其他数据存储到核心数据的代码。

- (IBAction)submitReportButton:(id)sender
{
    UrbanRangerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

    managedObjectContext = [appDelegate managedObjectContext];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PotholesDB" inManagedObjectContext:appDelegate.managedObjectContext];
    NSManagedObject *newPothole = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext];


    [newPothole setValue:self.relevantBody.text forKey:@"relevantBody"];
    [newPothole setValue:self.subjectReport.text forKey:@"subjectReport"];
    [newPothole setValue:self.detailReport.text forKey:@"detailReport"];
//    [newPothole setValue:self.imageView forKey:@"photo"];

    NSDate *now = [NSDate date];
    //NSLog(@"now : %@", now);
    NSString *strDate = [[NSString alloc] initWithFormat:@"%@", now];
    NSArray *arr = [strDate componentsSeparatedByString:@" "];
    NSString *str;
    str = [arr objectAtIndex:0];
    NSLog(@"now : %@", str);

    [newPothole setValue:now forKey:@"photoDate"];
    [newPothole setValue:self.latitudeLabel.text forKey:@"latitude"];
    [newPothole setValue:self.longitudeLabel.text forKey:@"longitude"];
    [newPothole setValue:self.addressLabel.text forKey:@"streetName"];
    [newPothole setValue:streeNameLocation forKey:@"location"];


    NSError *error;
    [managedObjectContext save:&error];

    UIAlertView *ll = [[UIAlertView alloc] initWithTitle:@"Saving" message:@"Saved data" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

    [ll show];
} 
4

7 回答 7

177

您可以使用 Binary Data 属性类型将图像存储在 Core Data 中。但是,您应该注意以下几点:

  • 始终将您的 UIImage 转换为可移植的数据格式,例如 png 或 jpg 例如:

    NSData *imageData = UIImagePNGRepresentation(image);

  • 在此属性上启用“允许外部存储”, 描述 如果达到某个阈值,Core Data 会将数据移动到外部文件。该文件也完全由 Core Data 管理,因此您不必担心。

  • 如果您遇到性能问题,请尝试将二进制数据属性移动到单独的实体。

  • 您应该在 NSManagedObject 子类的接口后面抽象到 NSData 的转换,因此您不必担心从 UIImage 到 NSData 的转换,反之亦然。

  • 如果您的图像与模型中的实体没有很强的相关性,我建议将它们存储在 Core Data 之外。

于 2013-05-22T08:39:56.087 回答
13

在 xcdatamodelId 子类中将图像实体声明为NSData... 您不能使用UIImage格式,因为图像数据是二进制格式。

@property (nonatomic, retain) NSData *imag;

在实现文件中..转换UIImageNSData

UIImage *sampleimage = [UIImage imageNamed:@"sampleImage.jpg"];

NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);

然后最后保存

[obj setValue:dataImage forKey:@"imageEntity"]; // obj refers to NSManagedObject
于 2013-11-27T07:00:15.037 回答
7

对于Swift 5Swift 4.2

  1. 转换UIImageData

    let imageData = image.jpegData(compressionQuality: 1.0)
    
  2. 保存到CoreData

    let object = MyEntity(context: managedContext)   //create object of type MyEntity
    object.image = imageData                         //add image to object
    
    do {
        try managedContext.save()                   //save object to CoreData
    } catch let error as NSError {
        print("\(error), \(error.userInfo)")
    }
    
于 2019-04-03T14:10:13.030 回答
4
- (void)imageChanged:(UIImage*)image{

    if (self.detailItem) {
        [self.detailItem setValue:UIImagePNGRepresentation(image) forKey:kSignatureImage];
    }
}

在这个非常简短的例子中。self是一个使用核心数据的视图控制器,self.detailItem 是通常的 NSManagedObject。在那个项目中,我没有为实体创建模型类,而是严格使用 KVC 模式来访问属性。正如您可能猜到的,该属性的名称"signatureImage"是我在 #define 常量中定义的kSignatureImage

这是从核心数据恢复图像的地方:

self.signatureCanvas.image =  [UIImage imageWithData:[self.detailItem valueForKey:kSignatureImage]];

同样,self是一个视图控制器,signatureCanvas是一个UIImageView子类,并且.image是它的常规image属性继承自UIImageView. detailItem,再次,是通常的NSManagedObject

该示例取自我目前正在从事的一个项目。

在核心数据中存储大型数据对象(如图像)或将它们分隔在文件中各有利弊。将它们存储在文件中意味着您有责任在删除相关数据对象时删除它们。这提供了编码开销,并且可能因编程错误而不稳定。另一方面,它可能会减慢底层数据库的速度。我还没有足够的经验来分享这种方法的性能。最后,占用的磁盘存储总量大致相同。

于 2013-05-22T08:44:13.507 回答
2

可以将图像作为 UIImage 存储在 Core Data 中。尽管这不被认为是一种好的做法,因为数据库不适合存储文件。我们不使用核心数据直接存储图像,而是使用文件路径来存储图像数据在手机上的位置。

无论如何,我在开发副项目时发现的最佳方法如下所示

  1. 将实体 codeGen 设置为 Manual/None

  2. 选择您想要的图像类型的属性并选择可转换的类型

  3. 输入自定义类标识符作为 UIImage

  4. 转到编辑器并选择创建 NSManagedObject 子类

  5. 该过程将根据您的实体数量创建 2 个 swift 文件(我只有 1 个实体)。现在,选择<EntityName> + CoreDataProperties.swift文件并导入 UIKit

如果在单击@NSManaged 公共变量的“跳转到定义UIImage definition”时,您的工作就完成了。

像您一样对实体执行操作,您将能够通过向下转换来获取、保存、编辑图像属性<EntityName>?.value(forKey: "<attributeName>") as? UIImage

我不得不使用实体作为NSManagedObject类型,并且由于某种原因无法直接从创建的子类访问图像。

于 2019-02-28T06:10:58.553 回答
1

很少有链接可以帮助您解决这个问题

https://stackoverflow.com/a/3909082/558000

在 CoreData 上保存和检索 UIImage

http://ootips.org/yonat/uiimage-in-coredata/

于 2013-05-22T07:44:53.697 回答
0

我不知道为什么要将图像存储在核心数据中,而 iOS 中还有其他可用的持久存储。如果您只想存储图像以用于缓存目的,则可以将其存储在文档目录或缓存目录中。快乐的编码...

请参考以下 URL,如何在文档目录中存储和检索图像。

http://www.wmdeveloper.com/2010/09/save-and-load-uiimage-in-documents.html

将图像保存到 Documents 目录并检索电子邮件附件

如何使用 Cocoa 创建临时文件?

于 2013-05-22T07:58:28.480 回答