简体   繁体   English

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

[英]How to store an image in core data

I'm new to iOS. 我是iOS新手。 I've been trying to make an application that will store an image captured from the camera into CoreData . 我一直在尝试制作一个应用程序,它将将从相机捕获的图像存储到CoreData I now know how to store data like NSString s, NSDate and other type but struggling to store an image. 我现在知道如何存储数据,例如NSStringNSDate和其他类型,但是却很难存储图像。 I've read so many articles saying you must write it to the disk and write to a file, but I can't seem to understand it. 我读过很多文章,说您必须将其写入磁盘并写入文件,但是我似乎无法理解。

The following code is the one i used to store other data to core data. 以下代码是我用来将其他数据存储到核心数据的代码。

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

You can store images in Core Data using the Binary Data attribute type. 您可以使用Binary Data属性类型将图像存储在Core Data中。 However you should be aware of a few things: 但是,您应该注意以下几点:

  • Always convert your UIImage to a portable data format like png or jpg For example: 始终将UIImage转换为可移植的数据格式,例如png或jpg例如:

    NSData *imageData = UIImagePNGRepresentation(image);

  • Enable "Allows external storage" on this attribute 在此属性上启用“允许外部存储” 描述 Core Data will move the data to an external file if it hits a certain threshold. 如果核心数据达到某个阈值,它将把数据移动到一个外部文件中。 This file is also completely managed by Core Data, so you don't have to worry about it. 该文件也由Core Data完全管理,因此您不必担心。

  • If you run into performance issues, try moving the Binary Data attribute to a separate entity. 如果遇到性能问题,请尝试将“二进制数据”属性移动到单独的实体。

  • You should abstract the conversion to NSData behind the interface of your NSManagedObject subclass, so you don't have to worry about conversions from UIImage to NSData or vice versa. 您应该在NSManagedObject子类的接口之后抽象到NSData的转换,因此您不必担心从UIImage到NSData的转换,反之亦然。

  • If your images are not strongly related to the entities in your model, I would suggest storing them outside of Core Data. 如果您的图像与模型中的实体关系不大,建议将其存储在Core Data之外。

In xcdatamodelId subclass declare image entity as NSData ... you can't use UIImage format because image data is in binary format. 在xcdatamodelId子类中,将图像实体声明为NSData ……您不能使用UIImage格式,因为图像数据是二进制格式。

@property (nonatomic, retain) NSData *imag;

In Implementation file.. convert UIImage to NSData 在实现文件中。将UIImage转换为NSData

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

NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);

Then finally save it 然后最后保存

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

For Swift 5 and Swift 4.2 对于Swift 5Swift 4.2

  1. convert UIImage to Data : UIImage转换为Data

     let imageData = image.jpegData(compressionQuality: 1.0) 
  2. save to CoreData : 保存到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)") } 
- (void)imageChanged:(UIImage*)image{

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

In this a very brief example. 在这个非常简单的例子中。 self is a view controller using core data and self.detailItem is the usual NSManagedObject. self是使用核心数据的视图控制器,self.detailItem是通常的NSManagedObject。 In that project I did not create model classes for the entities but strictly use the KVC pattern to access the attributes. 在那个项目中,我没有为实体创建模型类,而是严格使用KVC模式访问属性。 As you might guess, the attribute is named "signatureImage" which I had defined in an #define constant kSignatureImage . 您可能会猜到,该属性名为"signatureImage" ,我在#define常数kSignatureImage定义了该kSignatureImage

This is where the image is restored from core data: 这是从核心数据还原映像的位置:

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

Again, self is a view controller, signatureCanvas is a UIImageView subclass and .image is its regular image property inherited from UIImageView . 同样, self是视图控制器, signatureCanvasUIImageView子类, .image是其常规image属性,继承自UIImageView detailItem , again, is the usual NSManagedObject . detailItemdetailItem是通常的NSManagedObject

The example is taken from a project I am currently working on. 该示例取自我当前正在处理的项目。

There are pros and cons for storing large data objects like images in core data or having them separated in files. 将大型数据对象(例如图像)存储在核心数据中或将它们分隔在文件中有优缺点。 Storing them in files means that you are responsible for deleting them when the related data objects are deleted. 将它们存储在文件中意味着您有责任在删除相关数据对象时删除它们。 That provides coding overhead and may be volatile for programming errors. 这提供了编码开销,并且对于编程错误可能是易变的。 On the other hand, it may slow down the underlying database. 另一方面,它可能会降低基础数据库的速度。 I have not yet enough experience with this approach that I could share with respect to performance. 对于这种方法,我还没有足够的经验可以与我分享。 In the end, the disk storage occupied is about the same size in total. 最后,占用的磁盘存储空间总计大致相同。

It is possible to store images in Core Data as UIImage. 可以将图像作为UIImage存储在Core Data中。 Although this is not considered to be good practice as Databases are not meant for storing files. 尽管这不被认为是一种好习惯,因为数据库并不用于存储文件。 We don't use core data to store the images directly instead we use the file path to where the image data is stored on your phone. 我们不使用核心数据直接存储图像,而是使用文件路径存储图像数据到手机上。

Anyways, the best method I found out while developing a side-project is demonstrated below 无论如何,下面展示了我在开发附带项目时发现的最佳方法

  1. Set the entity codeGen to Manual/None 将实体codeGen设置为Manual / None

  2. Select the attribute you want to be of Image type and choose transformable as it's type 选择要为图像类型的属性,然后选择可变形的类型

  3. Enter Custom class identifier as UIImage 输入自定义类标识符作为UIImage

  4. Go to editor and select Create NSManagedObject Subclass 转到编辑器,然后选择创建NSManagedObject子类。

  5. The Process will create 2 swift files depending on the number of your entities(I only had 1 entity). 该流程将根据您的实体数量创建2个swift文件(我只有1个实体)。 Now, select the <EntityName> + CoreDataProperties.swift file and import UIKit 现在,选择<EntityName> + CoreDataProperties.swift文件并导入UIKit

If, on clicking Jump to Definition for the @NSManaged public var UIImage definition your work is done. 如果在@NSManaged公共var UIImage definition上单击“ 跳转到定义” ,则说明您的工作已完成。

Perform actions on the entities just like you would and you will be able to fetch, save, edit the image attribute by down-casting <EntityName>?.value(forKey: "<attributeName>") as? UIImage 就像您对实体执行操作一样,您可以通过向下转换<EntityName>?.value(forKey: "<attributeName>") as? UIImage来获取,保存和编辑图像属性<EntityName>?.value(forKey: "<attributeName>") as? UIImage <EntityName>?.value(forKey: "<attributeName>") as? UIImage . <EntityName>?.value(forKey: "<attributeName>") as? UIImage

I had to use the entity as NSManagedObject type and was for some reason not able to access the image directly from the created subclass. 我不得不将实体用作NSManagedObject类型,并且由于某种原因无法直接从创建的子类访问图像。

I don't know why you want to store image in core data, while there is other persistent storage available in iOS. 我不知道为什么要在核心数据中存储图像,而iOS中还有其他持久存储。 If you just want to store image for cache purpose, you can store it in document directory or cache directory. 如果仅出于存储目的而存储图像,则可以将其存储在文档目录或缓存目录中。 Happy Coding... 快乐编码...

Please refer below URL, How to store and retrieve images in document directory. 请参阅下面的URL,如何在文档目录中存储和检索图像。

http://www.wmdeveloper.com/2010/09/save-and-load-uiimage-in-documents.html 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? 如何使用Cocoa创建临时文件?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM