Saving UIImage Into Core Data Always Returns Nil when using ImagePickerView - Swift 3 - swift

I've been trying to save a single picture to an entity containing a single property titled "prof" and configured as a Binary Data type.
I go through the hoops to select a picture from UIImagePickerViewController, then I call up my method that handles saving the picture in Core Data in the desired NSData format.
My issue stems from loading the picture, in my loadImage method the entity for the image is not nil, meaning it does exist. However, I get nil when I try to parse the fetched NSData to a UIImage format to recreate the picture and then be able to use it.
Now i am using Swift 3 and Xcode 8, so far all the troubleshooting questions on here have the solution of casting the NSData to UImage like so:
let image : UIImage = UIImage(data: imageData)
however, xcode gives me a compiler error when I do this, and instead forces me to cast it as:
let image : UIImage = UIImage(data: (imageData as Data?)!)
which is where i get the nil that's throwing up my flow in the air... i've tried saving the data in many different ways, but still nothing.
if anyone could go through my following methods, see if i might be doing something wrong in the saving part, or the formating of NSData on the fetch method... anything would help.
My configuration:
-the prof property has "Allow external storage" set to true
-my persistent store is seeded blank at the app installation, meaning all the needed properties are already set up when the app is launched for the first time, but obviously set to nil until changed or modified by my various data flows.
-There is no other picture entity in my data model, this is the only one.
func saveProfilePicture(_ pic: UIImage){
let picData = UIImagePNGRepresentation(pic)
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first)
first?.setValue(picData, forKey: "prof")
try context.save()
} catch let err {
print(err)
}
}
func getProfilePicture() -> UIImage? {
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
var image : UIImage?
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first?.prof) as NSData
if let parsedImage : UIImage = UIImage(data: (first as Data?)!) as? UIImage {
image = parsedImage
}
} catch let err {
print(err)
}
return image
}
EDIT
The solution was found by noticing that in Swift 3, the UIImage class adheres to the Transformable protocol. Swapping my property type for the image from Binary Data to Transformable actually made it possible to save the UIImage as UIImage directly into Core Data without parsing it to another data type.
func saveProfilePicture(_ image: UIImage){
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first)
first?.prof = image
print(first)
coreDataManager.saveData()
} catch let err {
print(err)
}
}
func loadProfilePicture() -> UIImage? {
var image : UIImage?
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = records.first
if let img = first?.prof {
image = img as? UIImage
} else {
print("no image")
}
} catch let err {
print(err)
}
return image
}

Related

Why is UIImage? nil here?

I'm trying to bridge React and Swift code by passing a string for an image path, which I've verified appears correctly on the Native side, and having a bit of an issue. The image path comes from React as NSString, and my goal is to pass that as a String to a Native function that will ultimately send data back to React.
Here's a snippet of some code that handles part of this
classifyImage(value as String)
and some of the body of the classifiyImage is as follows:
#objc func classifyImage(_ image: String) {
let imageData = Data(base64Encoded: image, options: .ignoreUnknownCharacters)!
let uiImage = UIImage(data: imageData)
guard let orientation = CGImagePropertyOrientation(
rawValue: UInt32((uiImage?.imageOrientation.rawValue)!)) else {
return
}
...code
}
The exact error is at the line with the rawVale, reading
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Here's more info if it may help...
Image data can come from the camera as such image NSMutableString "file:///var/mobile/Containers/Data/Application/54691469-2196-444E-9B45-C0D6F2CABEBC/Library/Caches/Camera/EEC3631C-3E96-44DA-B258-411363A2F10C.jpg" 0x00000002815a8420
or from the phone's gallery image String "ph://8F109DC0-CE95-4D0A-9D11-1B2E9CE6B8D3/L0/001"
Image from a file
First, we need to turn the string into a URL, then the URL into data like so:
let url = URL(string: image)
do {
let data = try Data(contentsOf: url)
} catch {
print(e)
}
Then we can use it to create the image.
do {
let data = try Data(contentsOf: url)
let image = UIImage(data: data)
guard let orientation = CGImagePropertyOrientation(
rawValue: UInt32(image.imageOrientation.rawValue)) else {
print("that didn't work")
return
}
} catch {
print(e)
}

Display Image From Parse In Swift

I am trying to display the image I have stored in Buddy For Parse into a UIImageView, however I keep getting this error:
Could not cast value of type 'PFFileObject' (0x1045e0568) to 'NSString' (0x1041d75d8).
2019-04-13 18:15:09.869460-0500 PerfectLaptop[43839:3094232] Could not cast value of type 'PFFileObject' (0x1045e0568) to 'NSString' (0x1041d75d8).
I have already stored numerous strings into Parse, and am able to access them with no problems, and have stored the image I wanted to use also, however no matter what I try, I can't seem to get it to work. Many of the solutions I have found include casting the object as a PFFile, however this doesn't seem to exist anymore.
let query = PFQuery(className: "whichOneRecommended")
query.findObjectsInBackground { (objects, error) in
if error == nil
{
if let returnedobjects = objects
{
for object in returnedobjects
{
if (object["whichOne"] as! String).contains("\(self.whichOneJoined)")
{
self.laptopImage.image = UIImage(named: (object["laptopImage"]) as! String)
}
}
}
}
}
While the image file is viewable and downloadable in parse, I can't seem to actually have it be displayed in the imageview, and i want the image view to change programmatically by running this function as I have with other parts of the object.
Thanks in advance
The first thing to note is that PFFile has been renamed to PFFileObject.
You are trying to pass object["laptopImage"] which is a value of type Any to UIImage(named:) which can't be done because that function expects a String.
Firstly you need to create a constant of type PFFileObject:
let file = object["laptopImage"] as? PFFileObject
And then download the file data, create a UIImage from the PFFileObject and assign the image to the UIImageView:
file.getDataInBackground { (imageData: Data?, error: Error?) in
if let error = error {
print(error.localizedDescription)
} else if let imageData = imageData {
let image = UIImage(data: imageData)
self.laptopImage.image = image
}
}
Details on this can be found in the section on files in the iOS Guide.
guard let imageString = message,
let imageURL = URL(string: imageString) else { return }
do {
let imageData = try Data(contentsOf: imageURL)
image.image = UIImage(data: imageData)
} catch {
}

how to get image from Json in Swift

i'm a baby of xcode developer, and i really need a help. Below is one of my json data, that i have print in output, for the text i already got display into my screen, but now i'm trying to get the image from the server, and i don't know how to do it.
JSON :
"MoviePhotoL" : "\/Data\/UploadFile\/cnymv-01_1.jpg",
"MoviePhotoP" : "\/Data\/UploadFile\/cnymv-02_1.jpg"
XCODE:
let userImage = iP["MoviePhotoP"] as? String
cell.imageView.image = userImage (??????)
i know that String cannot be converted into UIImage, and i already try to convert it to NSData and convert the NSData to UIImage(data), but still not get the picture :'(.... can somebody please help me?? i really need some help
Those paths seem relative to another source.
You need to generate or get an absolute URL that will let you access the image.
Right now you have a simple string and that's all, you can't convert this to data or image.
You need a string that you can put in a browser and load an image.
Once you're able to do that, you can load the image in your app.
Example:
func getImage(from string: String) -> UIImage? {
//2. Get valid URL
guard let url = URL(string: string)
else {
print("Unable to create URL")
return nil
}
var image: UIImage? = nil
do {
//3. Get valid data
let data = try Data(contentsOf: url, options: [])
//4. Make image
image = UIImage(data: data)
}
catch {
print(error.localizedDescription)
}
return image
}
//1. Get valid string
let string = "https://images.freeimages.com/images/large-previews/f2c/effi-1-1366221.jpg"
if let image = getImage(from: string) {
//5. Apply image
cell.imageView.image = image
}
NOTE: Data(contentsOf:options:) is synchronous and can reduce performance. The larger the image, the longer it will lock it's thread.
Generally you would do such intensive tasks in a background thread and update UI on the main thread, but... to keep this answer simple, I chose not to show that.

Retrieving an image from Parse with Swift

I'm trying to retrieve an image and text from Parse. I'm able to retrieve the saved text but not the image. What am I doing wrong? Below is the code for the function that I want to retrieve the image. Thanks in advance.
func showImage() {
var query = PFQuery(className: "Description")
query.orderByDescending("ceatedAt")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
self.imageArray = [UIImage]()
if let objects = objects {
for imageObject in objects {
let userImage: UIImage? = (imageObject as! PFObject)["UserPhoto"] as? UIImage
if userImage != nil {
self.imageArray.append(userImage!)
}
}
}
self.tableView.reloadData()
}
}
It's tricky at first, but it gets a lot easier. Here's the code to make it work:
let userImage = (imageObject as! PFObject)["UserPhoto"] as! PFFile
userImage.getDataInBackgroundWithBlock {
(imageData, error) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
self.imageArray.append(userImage!)
} else {}
}}
the issue is that parse stores images as PFFiles, they're not directly images yet, think of it more as a URL than anything. You have to download the image, and then do something with it to make it work. You can't just directly cast it as a UIImage.
One thing to note (because this gave me trouble a while ago) is that the .getDataInBackgroundWithBlock method is asynchronous, so it'll run on it's own, and your code will continue before it's completed. Another thing to get used to.
Best of luck!

Error when trying to save image in NSUserDefaults using Swift

When i try to save an image in NSUserDefaults, the app crashed with this error.
Why? Is it possible to save an image with NSUserDefaults? If not, then how do I save the image?
Image...
Code...
var image1:UIImage = image1
var save1: NSUserDefaults = NSUserDefaults.standardUserDefaults()
save1.setObject(Info.Image1, forKey: "Image1")
save1.synchronize()
Log error...
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
NSUserDefaults isn't just a big truck you can throw anything you want onto. It's a series of tubes which only specific types.
What you can save to NSUserDefaults:
NSData
NSString
NSNumber
NSDate
NSArray
NSDictionary
If you're trying to save anything else to NSUserDefaults, you typically need to archive it to an NSData object and store it (keeping in mind you'll have to unarchive it later when you need it back).
There are two ways to turn a UIImage object into data. There are functions for creating a PNG representation of the image or a JPEG representation of the image.
For the PNG:
let imageData = UIImagePNGRepresentation(yourImage)
For the JPEG:
let imageData = UIImageJPEGRepresentation(yourImage, 1.0)
where the second argument is a CGFloat representing the compression quality, with 0.0 being the lowest quality and 1.0 being the highest quality. Keep in mind that if you use JPEG, each time you compress and uncompress, if you're using anything but 1.0, you're going to degrade the quality over time. PNG is lossless so you won't degrade the image.
To get the image back out of the data object, there's an init method for UIImage to do this:
let yourImage = UIImage(data:imageData)
This method will work no matter how you converted the UIImage object to data.
In newer versions of Swift, the functions have been renamed, and reorganized, and are now invoked as:
For the PNG:
let imageData = yourImage.pngData()
For the JPEG:
let imageData = yourImage.jpegData(compressionQuality: 1.0)
Although Xcode will autocorrect the old versions for you
In order to save UIImage in NSUserDefaults, you need to convert UIImage into NSData using UIImageJPEGRepresentation(image, 1) then save it in NSUserDefaults. And on the other side, while retrieving it on another ViewController (within that same application) you need to get NSData and then convert it into UIImage.
Here i am writing small code snippet in swift to demonstrate this. I tried this in XCODE 6.4
/*Code to save UIImage in NSUserDefaults on viewWillDisappear() event*/
override func viewWillDisappear(animated: Bool)
{
super.viewWillDisappear(animated)
//Get some image in image variable of type UIImage.
var image = ....
let defaults = NSUserDefaults.standardUserDefaults()
var imgData = UIImageJPEGRepresentation(image, 1)
defaults.setObject(imgData, forKey: "image")
}
/*Code to get Image and show it on imageView at viewWillAppear() event*/
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
let defaults = NSUserDefaults.standardUserDefaults()
if let imgData = defaults.objectForKey("image") as? NSData
{
if let image = UIImage(data: imgData)
{
//set image in UIImageView imgSignature
self.imgSignature.image = image
//remove cache after fetching image data
defaults.removeObjectForKey("image")
}
}
}
Updated for Swift 3:
If you want to save image in UserDefault used below lines of code save and retrieve the image;
To Save image in UserDefault:
if let image = response.result.value {
UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])
UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")
}
To Retrieve the image from UserDefault and set it to ImageView:
var mLogoImageView = UIImageView()
if let imageData = UserDefaults.standard.value(forKey: "key") as? Data{
let imageFromData = UIImage(data: imageData)
mLogoImageView.image = imageFromData!
}
Enjoy..!
In Swift 4 - 5
Set:
setImage(image: UIImage(named: "12")!)
func setImage(image : UIImage) {
UserDefaults.standard.set(image.jpegData(compressionQuality: 100), forKey: "key")
}
Get
func getImage() -> UIImage? {
if let imageData = UserDefaults.standard.value(forKey: "key") as? Data{
if let imageFromData = UIImage(data: imageData){
return imageFromData
}
}
return nil
}