0

I'm pretty new to swift and core data. So if this logic doesn't make sense, please let me know.

I'm trying to save user's images to core data and be able to delete selected one. I have Entity "Media", attribute "photo" type "binary data"

Here I convert UIImage to NSData

let data = UIImagePNGRepresentation(addedImage!) as NSData?

And save it.

let newPhoto = NSEntityDescription.insertNewObject(forEntityName: "Media", into: context)
newPhoto.setValue(imageData, forKey: "photo")

Here I try to retrieve that one selected image from core data using predicate

func deleteImage(imageData: NSData) {

        let context = appDelegate.persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Media")
        request.returnsObjectsAsFaults = false
        request.predicate = NSPredicate(format: "photo =%@", imageData)

        do {
            let results = try context.fetch(request)
           ...

And I'm getting this error message.

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[OS_dispatch_data _bytesPtrForStore]: unrecognized selector sent to instance

Saving and getting all images from entity "Media" is working perfectly. I just can't get the specific one.

Any thoughts/suggestions? Thanks.

terk
  • 3
  • 2
  • In this tutorial you can find how to store image and fetch https://www.raywenderlich.com/145860/core-data-migrations-tutorial-lightweight-migrations-2 – Prashant Tukadiya Apr 14 '17 at 04:39

2 Answers2

1

Saving images like this, with external storage enabled for the property, can be OK. But there are some very unusual things going on here.

The common approach would be to have the image be part of an entity with other information, but not as the primary value of the entity. For example an entity type that represents a person and has name, address, etc, and a picture. Storing just a picture in an entity is kind of weird. You're not getting much of anything from using Core Data over something simpler. If nothing else I'd guess you had a photo ID, or title, or some other data in the entity.

The second thing relates to that-- it's extremely unusual to try to fetch using a predicate based on a binary data property. I guess it might work but only if you can ensure that the predicate value is identical to one in the persistent store all the way through-- not a single bit changed in the binary blob. That might be true but I wouldn't rely on UIKit not doing something along the way that makes it subtly different. I've never seen that particular error message but I'm not surprised that this isn't working.

Finally, it's also unusual (though not quite so strange as the above) to delete an object based on a fetch request. You would have fetched these objects before to get the images. Why fetch the same object again just to delete it? Delete the one you already fetched.

A more reliable approach would be to at least include a unique ID in the entity, which might be an integer or a UUID or whatever else works for you. Fetch this entity and display images using the photo property. When you want to delete one, take the managed object from your fetch and tell the context to delete that one. Or if fetching is necessary for some reason, use the unique ID in the predicate instead of the binary data.

Tom Harrington
  • 69,312
  • 10
  • 146
  • 170
  • 'You would have fetched these objects before to get the images. Why fetch the same object again just to delete it? Delete the one you already fetched.' Can I save my fetched [NSManagedObject] somewhere and delete the one I want whenever? – terk Apr 15 '17 at 03:15
  • 'use the unique ID in the predicate instead of the binary data' Do you mean have another attribute of unique ID? I thought binary data is the type needed to save images. Thanks for your help! – terk Apr 15 '17 at 03:17
  • If you want to save the managed object **and** delete it then I really have no idea what you're trying to do. A binary attribute is necessary to save an image but you can have more than one attribute on an entity. – Tom Harrington Apr 15 '17 at 03:53
  • 'You would have fetched these objects before to get the images. Why fetch the same object again just to delete it? Delete the one you already fetched.' Okay then I don't understand what you are saying here. I thought in order to delete something in core data you need to fetch that object first. Fetching the images to display and fetching the image to delete are two different actions. They don't happen sequentially. – terk Apr 15 '17 at 19:56
0

You better stop doing it. Saving heavy data (image, audio, video, ...) to core data will greatly decrease fetching speed when you have more records. Instead, save image to application folder, and then only save its url to core data.

Community
  • 1
  • 1
Luan Lai
  • 473
  • 2
  • 10
  • Thanks! I'll look into it. – terk Apr 15 '17 at 03:18
  • No, you can still use core data. There are parameters like "Allows external storage" for binary data attributes; there you can avoid having to link/load the image manually and just use core data and all their features like relationships and so on. – smat88dd Jul 07 '17 at 14:05