So speichern Sie ein Bild in Kerndaten

74

Ich bin neu in iOS. Ich habe versucht, eine Anwendung zu erstellen, in der ein von der Kamera aufgenommenes Bild gespeichert wird CoreData. Ich weiß jetzt, wie man Daten wie NSStrings NSDateund andere Typen speichert, habe aber Schwierigkeiten, ein Bild zu speichern. Ich habe so viele Artikel gelesen, dass Sie es auf die Festplatte schreiben und in eine Datei schreiben müssen, aber ich kann es anscheinend nicht verstehen.

Der folgende Code ist der, mit dem ich andere Daten in Kerndaten gespeichert habe.

- (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];
} 
Sipho Koza
quelle
1
Ihr Bild wird wahrscheinlich in einem UIImageObjekt gespeichert . Wenn ja, können Sie es folgendermaßen in ein NSDataObjekt konvertieren : NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(myUIImage)];Ich glaube, das Speichern von NSDataObjekten CoreDataist nicht wirklich schwierig.
Rdurand
7
IMO, das Speichern von Binärdaten in einer Datenbank ist im Allgemeinen nicht ratsam. Das Abrufen ist langsamer als das Lesen von der Festplatte. Da Core Data wahrscheinlich intern SQLite verwendet, werden Dateien effektiv in einer Datei (der SQLite-Datenbank) gespeichert, wodurch die Größe sehr schnell zunimmt und die DB-Vorgänge erheblich verlangsamt werden. Ich würde nur den Pfad in der Datenbank speichern und dann die Bilder auf der Festplatte speichern.
dandan78
Ich stimme dandan78 zu. Es ist nicht ratsam, die Bilder im Geschäft zu speichern. Sie sollten stattdessen auf jeden Fall den Pfad zum Bild speichern.
Mikael
Sie können die Daten des Bildes mithilfe von UIImagePNGRepresentaionoder UIImageJPEGrepresentation abrufen und die Daten speichern. Wenn Sie die Daten abrufen, erstellen Sie das Bild mit +imageWithData:. Natürlich können Sie sie in Dateien speichern und einfach den Dateinamen speichern. Ich habe beides gemacht. Geben Sie mir eine Minute und ich werde nach Code-Sniplets suchen.
Hermann Klecker
1
Komm darüber hinweg. Sie können Bilder je nach Größe in Core Data speichern. Wenn sie unter 100.000 komprimiert sind, müssen sie sich nicht einmal in einer externen Datei befinden. Wir finden, dass die Leistung in Ordnung ist.
RegularExpression

Antworten:

173

Sie können Bilder in Core Data mithilfe des Attributtyps Binärdaten speichern. Sie sollten sich jedoch einiger Dinge bewusst sein:

  • Konvertieren Sie Ihr UIImage immer in ein tragbares Datenformat wie png oder jpg. Zum Beispiel:

    NSData *imageData = UIImagePNGRepresentation(image);

  • Aktivieren Sie "Ermöglicht externen Speicher" für dieses Attribut. Beschreibung Core Data verschiebt die Daten in eine externe Datei, wenn sie einen bestimmten Schwellenwert erreichen. Diese Datei wird auch vollständig von Core Data verwaltet, sodass Sie sich darüber keine Sorgen machen müssen.

  • Wenn Sie auf Leistungsprobleme stoßen, versuchen Sie, das Attribut Binärdaten in eine separate Entität zu verschieben.

  • Sie sollten die Konvertierung in NSData hinter der Schnittstelle Ihrer NSManagedObject-Unterklasse abstrahieren, damit Sie sich nicht um Konvertierungen von UIImage nach NSData oder umgekehrt kümmern müssen.

  • Wenn Ihre Bilder nicht stark mit den Entitäten in Ihrem Modell verbunden sind, würde ich empfehlen, sie außerhalb von Core Data zu speichern.

jansenmaarten
quelle
Für "Sie sollten die Konvertierung in NSData hinter der Schnittstelle Ihrer NSManagedObject-Unterklasse abstrahieren, damit Sie sich keine Gedanken über Konvertierungen von UIImage zu NSData machen müssen oder umgekehrt." Könnten Sie näher erläutern, wie das geht?
Doug Smith
8
Erstellen Sie eine Methode zum Festlegen des Bildes - (void) setImage: (UIImage *) image; Wahrscheinlich in einer Kategorie. Verwenden Sie bei dieser Methode UIImagePNGRepresentaion oder UIImageJPEGrepresentation, sodass Sie dies nur einmal tun müssen (Sie möchten nicht als PNG speichern und versuchen, in JPEG zu konvertieren).
Kevin
12

In der Unterklasse xcdatamodelId deklarieren NSDataSie die Bildentität als ... Sie können das UIImageFormat nicht verwenden , da die Bilddaten im Binärformat vorliegen.

@property (nonatomic, retain) NSData *imag;

In der Implementierungsdatei .. konvertieren UIImagenachNSData

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

NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);

Dann speichere es endlich

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

Für Swift 5 und Swift 4.2

  1. konvertieren UIImagezu Data:

    let imageData = image.jpegData(compressionQuality: 1.0)
    
  2. Speichern unter 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)")
    }
    
nomnom
quelle
4
- (void)imageChanged:(UIImage*)image{

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

In diesem ein sehr kurzes Beispiel. selfist ein Ansichts-Controller, der Kerndaten verwendet, und self.detailItem ist das übliche NSManagedObject. In diesem Projekt habe ich keine Modellklassen für die Entitäten erstellt, sondern ausschließlich das KVC-Muster verwendet, um auf die Attribute zuzugreifen. Wie Sie sich vorstellen können, heißt das Attribut, "signatureImage"das ich in einer # define-Konstante definiert habe kSignatureImage.

Hier wird das Image aus den Kerndaten wiederhergestellt:

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

Auch hier selfhandelt es sich um einen Ansichtscontroller, signatureCanvasum eine UIImageViewUnterklasse und .imageum dessen reguläre imageEigenschaft UIImageView. detailItemist wieder das übliche NSManagedObject.

Das Beispiel stammt aus einem Projekt, an dem ich gerade arbeite.

Es gibt Vor- und Nachteile, große Datenobjekte wie Bilder in Kerndaten zu speichern oder in Dateien zu trennen. Wenn Sie sie in Dateien speichern, sind Sie dafür verantwortlich, sie zu löschen, wenn die zugehörigen Datenobjekte gelöscht werden. Dies bietet Codierungsaufwand und kann für Programmierfehler flüchtig sein. Andererseits kann dies die zugrunde liegende Datenbank verlangsamen. Ich habe noch nicht genug Erfahrung mit diesem Ansatz, die ich in Bezug auf die Leistung teilen könnte. Am Ende ist der belegte Speicherplatz insgesamt ungefähr gleich groß.

Hermann Klecker
quelle
1

Es ist möglich, Bilder in Core Data als UIImage zu speichern. Dies wird zwar nicht als bewährte Methode angesehen, da Datenbanken nicht zum Speichern von Dateien vorgesehen sind. Wir verwenden keine Kerndaten, um die Bilder direkt zu speichern, sondern verwenden den Dateipfad, in dem die Bilddaten auf Ihrem Telefon gespeichert sind.

Wie auch immer, die beste Methode, die ich bei der Entwicklung eines Nebenprojekts herausgefunden habe, wird unten gezeigt

  1. Setzen Sie den Entitätscode Gen auf Manuell / Keine

  2. Wählen Sie das Attribut aus, dessen Bildtyp Sie sein möchten, und wählen Sie als Typ transformierbar aus

  3. Geben Sie die benutzerdefinierte Klassenkennung als UIImage ein

  4. Gehen Sie zum Editor und wählen Sie NSManagedObject-Unterklasse erstellen

  5. Der Prozess erstellt 2 schnelle Dateien, abhängig von der Anzahl Ihrer Entitäten (ich hatte nur 1 Entität). Wählen Sie nun die <EntityName> + CoreDataProperties.swiftDatei aus und importieren Sie UIKit

Wenn Sie auf " Zur Definition springen" für die öffentliche Variable "@NSManaged" klicken, ist UIImage definitionIhre Arbeit erledigt.

Führen Sie Aktionen für die Entitäten wie gewohnt aus, und Sie können das Bildattribut durch Downcasting abrufen, speichern und bearbeiten <EntityName>?.value(forKey: "<attributeName>") as? UIImage.

Ich musste die Entität als NSManagedObjectTyp verwenden und konnte aus irgendeinem Grund nicht direkt von der erstellten Unterklasse auf das Bild zugreifen.

Utkarsh Jaiswal
quelle
0

Ich weiß nicht, warum Sie Bilder in Kerndaten speichern möchten, während in iOS anderer dauerhafter Speicher verfügbar ist. Wenn Sie das Image nur für Cachezwecke speichern möchten, können Sie es im Dokumentverzeichnis oder im Cache-Verzeichnis speichern. Viel Spaß beim Codieren ...

Weitere Informationen finden Sie unter URL, Speichern und Abrufen von Bildern im Dokumentverzeichnis.

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

Speichern des Bildes im Verzeichnis "Dokumente" und Abrufen für E-Mail-Anhänge

Wie erstelle ich eine temporäre Datei mit Cocoa?

Mangesh
quelle
1
Viele gute Gründe. Möglicherweise möchten Sie Ihre Datenbank kopieren und an ein anderes Gerät senden. Viel einfacher, wenn es in einem SQLite-Laden sitzt. Und insgesamt ist es einfacher zu verwalten, ohne viel beschissenen Code zu pflegen.
RegularExpression