5

For some reason I can't figure out how to save images to core data and fetch them again. I have a feeling it's something about my types but have a look:

Image is saved as Binary Data and stored in External Record File

I get my data from an api call to my server. It returns a base64 string. Here is where I get the data:

updateAccessTokenOnly(newAccessToken: aToken!)
saveImageToDB(brandName: imageBrandName, image: data! )

Here I save it to my DB:

func saveImageToDB(brandName: String, image: Data) {
    dropImages(){tableDropped in
        let managedContext = getContext()
        let entity = NSEntityDescription.entity(forEntityName: "CoffeeShopImage", in: managedContext)!
        let CSI = NSManagedObject(entity: entity, insertInto: managedContext)

        CSI.setValue(image, forKey: "image")
        CSI.setValue(brandName, forKey: "brandName")

        do {
            try managedContext.save()
            print("saved!")
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
        }
    }
}

then to fetch it:

    func getImageFromDB(callback: @escaping (_ image: UIImage)-> ()) {

    let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: "CoffeeShopImage")

    do {
        let searchResults = try getContext().fetch(fetchRequest)

        for images in searchResults {
            print("vi når her ned i get image")
            if (images.value(forKey: "brandName")! as! String == "Baresso"){
                print(images.value(forKey: "brandName")! as! String)

                let image: Data = images.value(forKey: "image")! as! Data
                let decodedimage = UIImage(data: image)

                callback(decodedimage!)

            }
        }
    } catch {
        print("Error with request: \(error)")
    }
}

Full error log:

https://docs.google.com/document/d/1gSXE64Sxtzo81eBSjv4bnBjBnnmG4MX2tuvNtnuJDIM/edit?usp=sharing

Hope someone can help. Thanks in advance!

UPDATED

So I uninstalled the app and then the code above worked. However the pictures come out blue? (yes I've checked that the pictures sent from the database are correct).

Any solution?

Pictures fetched from CoreData

Steffen L.
  • 149
  • 2
  • 14
  • 2
    Better approach would be storing images in `DocumentDirectory` or `Library` and store the path to image in CoreData as string. Storing images (as Binary Data or Transformable) in CoreData will make encoding/decoding a heavy operation. – viral Feb 27 '17 at 11:33

3 Answers3

12

replace

let image: Data = images.value(forKey: "image")! as! Data
let dataDecoded : Data = Data(base64Encoded: image, options: [])!
let decodedimage = UIImage(data: dataDecoded)

with

let image: Data = images.value(forKey: "image")! as! Data
let decodedimage = UIImage(data: image)

Base64 is a way to to convert data to a string. There is no reason to use it here. You already have the data from the database you just want to convert it to a UIImage.

also change

let image = data?.base64EncodedData()
saveImageToDB(brandName: imageBrandName, image: image!)

to

saveImageToDB(brandName: imageBrandName, image: data!)

base64EncodedData is turning the data from image data into a utf-8 encoded based64encoded string. There is no reason for that.

You should get the base64 encoded string from server, convert it to data and then you never need base64 again. Read and write data to your database, and after you read it convert it to a UIImage. Base64 is an encoding method to transfer data. If you are not talking to the server there is no reason to use base64.

Jon Rose
  • 8,373
  • 1
  • 30
  • 36
  • 1
    Hey Jon, my new best friend hehe. It seems that my error I get is from saving. I tried saving it as a string instead of data. Which seemed to save alright, however when I fetched my images they came out as blue squares instead of, well images. But at the moment, it won't save with the code above. – Steffen L. Feb 27 '17 at 11:28
  • Should I infact store the data as a String instead of Binary Data? Or? – Steffen L. Feb 27 '17 at 11:30
  • Hi Jon, I made the changes you suggested, however I am still getting the error on save. I have updated the code and also put the whole error log. – Steffen L. Feb 27 '17 at 16:27
  • Which means I can't even test the fetch, because it won't save. – Steffen L. Feb 27 '17 at 16:32
  • The error "Can't find or automatically infer mapping model for migration" means that you need to delete you app and reinstall. – Jon Rose Feb 28 '17 at 06:36
  • You were right, I uninstalled the app and it worked. However the pictures only turn out blue? – Steffen L. Feb 28 '17 at 07:54
  • Is the width and heigh of the UIImage what you expect? – Jon Rose Feb 28 '17 at 08:09
  • I actually don't know the dimensions of the images right now. Could this be the result of them being too big? – Steffen L. Feb 28 '17 at 08:10
  • Then again I am gonna need the pictures to adjust to the screen size so it's set to "scale to fill" in the attributes inspector of the xib. So I imagine it is okay that the images are not the exact same size? – Steffen L. Feb 28 '17 at 08:25
  • I am wondering if the data used to create the image is correct, or if it is a problem with the displaying of the image. If the image size is correct it would imply that there is some display problem. If the image size is not correct then perhaps the server is sending bad data (perhaps a non-supported format). Or you may have base64 data when you want imageData. – Jon Rose Feb 28 '17 at 08:35
  • Hmm my collegue has this working on Android. So the pictures sent from the server works. He informs me the api call returns a base64 string. The way I save it and fetch it makes me wonder if it's the latter, and it is base64 data I am trying to display? – Steffen L. Feb 28 '17 at 08:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/136827/discussion-between-steffen-lefort-and-jon-rose). – Steffen L. Feb 28 '17 at 08:43
2

After the suggested corrections from Jon Rose all I needed was to add

.withRenderingMode(.alwaysOriginal)

to where I was showing my picture and the code worked.

Steffen L.
  • 149
  • 2
  • 14
2

User Entity

Saving Image:

 guard let managedObjectContext = managedObjectContext else { return }

    // Create User
    let user = User(context: managedObjectContext)

    // Configure User
    user.name = "name"
    user.about = "about"
    user.address = "Address"
    user.age = 30
    if let img = UIImage(named: "dog.png") {
        let data = img.pngData() as NSData?
        user.image = data
    }

Fetching Image:

// Create Fetch Request
    let fetchRequest: NSFetchRequest<User> = User.fetchRequest()

    // Configure Fetch Request
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
    let users = try! managedContext.fetch(fetchRequest)
    let user: User = users.first as! User
    if let imageData = user?.image {
            imgView.image = UIImage(data: imageData as Data)
    }
Yogendra Singh
  • 2,063
  • 25
  • 20