如何在核心数据中存储图像

时间:2013-05-22 07:24:35

标签: ios objective-c core-data

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

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

- (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];
} 

7 个答案:

答案 0 :(得分:159)

您可以使用二进制数据属性类型将图像存储在Core Data中。 但是你应该知道一些事情:

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

    NSData *imageData = UIImagePNGRepresentation(image);

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

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

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

  • 如果您的图片与模型中的实体没有密切关系,我建议将它们存储在Core Data之外。

答案 1 :(得分:12)

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

@property (nonatomic, retain) NSData *imag;

在实施文件中..将UIImage转换为NSData

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

NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);

然后最后保存

[obj setValue:dataImage forKey:@"imageEntity"]; // obj refers to NSManagedObject

答案 2 :(得分: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是视图控制器,signatureCanvasUIImageView子类,.image是从image继承的常规UIImageView属性。 detailItem再一次是NSManagedObject

该示例来自我目前正在进行的项目。

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

答案 3 :(得分:1)

答案 4 :(得分:0)

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

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

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

Saving image to Documents directory and retrieving for email attachment

How do I create a temporary file with Cocoa?

答案 5 :(得分:0)

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

无论如何,下面展示了我在开发附带项目时发现的最佳方法

  1. Set the entity codeGen to Manual/None

  2. 选择要为图像类型的属性,然后选择transformable作为其类型

  3. Enter Custom class identifier as UIImage

  4. 转到编辑器,然后选择Create NSManagedObject Subclass

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

如果点击Jump to Definition作为@NSManaged公共变量UIImage definition的工作就完成了。

对实体执行操作就像您将要进行的一样,您将可以通过向下广播<EntityName>?.value(forKey: "<attributeName>") as? UIImage来获取,保存和编辑图像属性。

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

答案 6 :(得分:0)

对于 Swift 4.2

  1. UIImage转换为Data

    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)")
    }