Як зберігати зображення в основних даних


74

Я новачок у iOS. Я намагався зробити програму, яка зберігатиме зображення, зняте з камери CoreData. Тепер я знаю, як зберігати дані, такі як NSStrings 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];
} 

1
Ваше зображення, ймовірно, зберігається в UIImageоб'єкті. Якщо так, ви можете перетворити його в NSDataоб'єкт за допомогою цього: NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(myUIImage)];я вважаю, що зберігати NSDataоб'єкти в CoreDataних насправді не складно.
рдуранд і

7
ІМО зберігати двійкові дані у базі даних, як правило, недоцільно. Отримати це буде повільніше, ніж читання з диска, і оскільки Core Data, ймовірно, буде використовувати SQLite внутрішньо, ви ефективно зберігатимете файли всередині файлу (SQLite DB), змушуючи його розширюватися в розмірі дуже швидко і значно сповільнюючи операції з БД. Я просто зберігав би шлях у БД, а потім зберігав зображення на диск.
dandan78

Я згоден з dandan78. Нерозумно зберігати зображення в магазині. Натомість слід обов’язково зберегти шлях до зображення.
Мікаель

Ви можете отримати дані, що використовують зображення, UIImagePNGRepresentaionабо презентацію UIImageJPEG та зберегти дані. Коли ви отримуєте дані, які створюєте за допомогою зображення +imageWithData:. Звичайно, ви можете зберегти їх у файлах і просто зберегти ім'я файлу. Я зробив і те, і інше. Дайте мені хвилинку, і я пошукаю фрагменти коду.
Герман Клекер

1
Закінчуй з цим. Ви можете зберігати зображення в Основних даних залежно від розміру. Якщо вони стиснуті до 100 тис., Вони навіть не повинні бути у зовнішньому файлі. Ми вважаємо, що продуктивність чудова.
RegularExpression

Відповіді:


173

Ви можете зберігати зображення в Основних даних, використовуючи тип атрибута Binary Data. Однак вам слід знати декілька речей:

  • Завжди перетворюйте свій UIImage у переносний формат даних, такий як png або jpg Наприклад:

    NSData *imageData = UIImagePNGRepresentation(image);

  • Увімкніть параметр «Дозволяє зовнішнє зберігання» для цього атрибута опис Основні дані будуть переміщувати дані у зовнішній файл, якщо він досягне певного порогу. Цим файлом також повністю керує Core Data, тому вам не доведеться про це турбуватися.

  • Якщо у вас виникли проблеми з продуктивністю, спробуйте перенести атрибут Binary Data в окрему сутність.

  • Вам слід абстрагувати перетворення в NSData за інтерфейсом вашого підкласу NSManagedObject, тому вам не доведеться турбуватися про перетворення з UIImage в NSData або навпаки.

  • Якщо ваші зображення не сильно пов'язані з сутностями у вашій моделі, я б запропонував зберігати їх поза Основними даними.


Для "Ви повинні абстрагувати перетворення в NSData за інтерфейсом вашого підкласу NSManagedObject, щоб вам не довелося турбуватися про перетворення з UIImage в NSData або навпаки." Ви могли б детальніше розповісти, як це зробити?
Doug Smith

8
Створіть один метод для встановлення зображення - (void) setImage: (UIImage *) image; Можливо, в категорії. У цьому методі використовуйте UIImagePNGRepresentaion або UIImageJPEGrepresentation, щоб вам потрібно було зробити це лише один раз (ви не хочете зберігати як PNG і намагатися конвертувати в JPEG).
Кевін

13

У підкласі 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

6

Для Swift 5 та 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)")
    }
    

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.

Приклад взятий з проекту, над яким я зараз працюю.

Є плюси і мінуси для зберігання великих об’єктів даних, таких як зображення, в основних даних або їх розділення у файлах. Зберігання їх у файлах означає, що ви несете відповідальність за їх видалення, коли пов’язані об’єкти даних видаляються. Це забезпечує накладні витрати на кодування і може бути мінливим для помилок програмування. З іншого боку, це може уповільнити базову базу даних. У мене ще недостатньо досвіду з цим підходом, яким я міг би поділитися щодо продуктивності. Врешті-решт, загальний обсяг зайнятого дискового сховища приблизно однаковий.



1

Можна зберігати зображення в Основних даних як UIImage. Хоча це не вважається доброю практикою, оскільки Бази даних не призначені для зберігання файлів. Ми не використовуємо основні дані для безпосереднього зберігання зображень, натомість використовуємо шлях до файлу, де дані зображень зберігаються на вашому телефоні.

У будь-якому випадку, найкращий метод, який я знайшов під час розробки побічного проекту, продемонстрований нижче

  1. Встановіть для сутності codeGen значення Manual / None

  2. Виберіть атрибут, який ви хочете мати, типу зображення, і виберіть трансформований як його тип

  3. Введіть власний ідентифікатор класу як UIImage

  4. Перейдіть до редактора та виберіть Створити підклас NSManagedObject

  5. Процес створить 2 швидких файли залежно від кількості ваших об’єктів (у мене було лише 1 об’єкт). Тепер виберіть <EntityName> + CoreDataProperties.swiftфайл та імпортуйте UIKit

Якщо після натискання кнопки Перейти до визначення для загальнодоступної змінної @NSManaged UIImage definitionваша робота закінчена.

Виконуйте дії над сутностями так само, як і ви, і ви зможете отримати, зберегти, відредагувати атрибут зображення шляхом лиття вниз <EntityName>?.value(forKey: "<attributeName>") as? UIImage.

Мені довелося використовувати сутність як NSManagedObjectтип, і я з якихось причин не мав доступу до зображення безпосередньо зі створеного підкласу.


0

Я не знаю, чому ви хочете зберігати зображення в основних даних, а в iOS є інший постійний накопичувач. Якщо ви просто хочете зберегти зображення для кешування, ви можете зберегти його в каталозі документів або каталозі кешу. Щасливого кодування ...

Будь ласка, зверніться до URL-адреси нижче, як зберігати та отримувати зображення в каталозі документів.

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

Збереження зображення в каталозі Документи та отримання для вкладення електронної пошти

Як створити тимчасовий файл за допомогою какао?


1
Багато вагомих причин. Можливо, ви захочете скопіювати свою базу даних і надіслати її на інший пристрій. Набагато простіше, якщо він сидить у магазині sqlite. І загалом просто простіше керувати без великої кількості дерьмового коду, який можна підтримувати.
RegularExpression
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.