How to save images to Parse? - ios

For some odd reason, my images have stopped saving to parse. Before, my code worked fine and I have not made any changes to it at all.
Here is my code:
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
}else {
println(error)
}
})
Everything else is stored perfectly, but what's the issue with my image data?
Thanks!

In your code you are not saving parseImageFile, so first parseImageFile.SaveInBackground and on success set it to posts and then save posts as well
Should be something like this
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
parseImageFile.saveInBackgroundWithBlock({
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
})
}else {
println(error)
}
})
I haven't test this code on editor you may find some syntax error, but it should be something like this...
so things is when you create parseImageFile and then saveInBackground and inside block set it posts and then save post again

I've checked your code and it's works fine.
let image = UIImage(named: "img.jpg")
let data = UIImagePNGRepresentation(image)
let file = PFFile(name: "img", data: data)
let parseObj = PFObject(className: "testClass")
parseObj["text"] = "hello"
parseObj["image"] = file
parseObj.saveInBackgroundWithBlock { (_, _) -> Void in }
Try this, if this code will be works - easiest way for you is remove "Product" table and create it again.

Related

Swift 3 upload image to Parse Server

I'm trying to upload an image to Parse Server usinf PFFile. I'm not having issues uploading it manually from Parse Dashboard and retrieving it from the app. But if I try to upload a new one with this method, the image is not being updated.
The rest of fields are beeing uploaded correctly (name, lastname, username and email)
Save method:
#IBAction func saveBtnPressed(_ sender: Any) {
print("Start saving...")
let imageData = UIImagePNGRepresentation(profilePic.image!)
print ("imageData value:")
print(imageData!)
let imageFile = PFFile(name:"avatar.png", data:imageData!)
print ("imageFile value:")
print(imageFile!)
let query = PFQuery(className: "_User")
query.whereKey("username", equalTo: (PFUser.current()?.username)!)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
object["name"] = self.nameFld.text
object["lastname"] = self.lastnameFld.text
object["username"] = self.emailFld.text
object["email"] = self.emailFld.text
object["avatar"] = imageFile
print(object)
object.saveInBackground()
}
}
})
}
Output:
Start saving...
imageData value:
8358983 bytes
(lldb)
To make this work you will need to upload picture only first and then reference it to the user
let imageData = UIImagePNGRepresentation(profilePic.image!)
print ("imageData value:")
print(imageData!)
let imageFile = PFFile(name:"avatar.png", data:imageData!)
print ("imageFile value:")
print(imageFile!)
imageFile.saveInBackground { (result, error) in
if let error = error{
print(error)
}else{
let query = PFQuery(className: "_User")
query.whereKey("username", equalTo (PFUser.current()?.username)!)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
object["name"] = self.nameFld.text
object["lastname"] = self.lastnameFld.text
object["username"] = self.emailFld.text
object["email"] = self.emailFld.text
object["avatar"] = imageFile
print(object)
object.saveInBackground()
}
}
})
}
}
}
Be aware that in the above example the file is always uploaded to the server even if no users match the query so consider uploading file only after getting query results.
There is no need to query current user. You can do it as follows:
#IBAction func saveBtnPressed(_ sender: AnyObject) {
let userToUpdate = PFUser.current()!
userToUpdate["name"] = self.nameFld.text
userToUpdate["email"] = self.emailFld.text
userToUpdate["username"] = self.emailFld.text
// Save Avatar
if profilePic.image != nil {
let imageData = UIImageJPEGRepresentation(profilePic.image!, 0.5)
let imageFile = PFFile(name:"avatar.jpg", data:imageData!)
userToUpdate["avatar"] = imageFile
}
// Saving block
userToUpdate.saveInBackground(block: { (succ, error) in
if error == nil {
print("Your Profile has been updated!")
} else {
print("Failed")
}})
}

How to retrieve a image from Parse?

I'm trying to get an image from a parse server that is hosted on Heroku. So far I have gotten the Text values but the images are the only problem.
Here is my code so far:
// Getting Info from servers
let dataQ = PFQuery(className: "message")
dataQ.findObjectsInBackground { (objects: [PFObject]?, error: Error?) -> Void in
if error == nil {
for object in objects! {
self.sentFromLabel.text = object["sender"] as? String
// Get Image from server
object["Picture"].getDataInBackgroundWithBlock
}
} else {
print(error)
}
}
So far when I use .getDataInBackgroundWithBlock it gives me an error. I have no clue why. What is the Swift 3 version to allow me to get an image from the server?
Here is a swift 3 example!
#IBOutlet weak var fullImage : UIImageView!
//place this in your for loop
let imageFile = (object.object(forKey: "ImageFile") as? PFFile)
imageFile?.getDataInBackground (block: { (data, error) -> Void in
if error == nil {
if let imageData = data {
//Here you can cast it as a UIImage or do what you need to
self.fullImage.image = UIImage(data:imageData)
}
}
})

One image pulled from Parse when there are actually two : weird error.

I have the following function that's suppose to pull images from a class in Parse. The number of images in the class is two and the print line print(objectsFound?.count) prints out 2 - confirming there are two images
func loadAllObjects() {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .NetworkElseCache
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
discoveryQuery.findObjectsInBackgroundWithBlock { (objectsFound: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print(objectsFound?.count) //This prints out 2
for var i = 0; i < objectsFound?.count; i++ {
if let imageFileFound = objectsFound![i].objectForKey("workoutImage") as? PFFile {
imageFileFound.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
self.arrayOfWorkoutImages = [UIImage(data:imageData!)!]
}
}
}
}
} else {
//An error Occured
self.showFailureAlert("😐 Failed to get workout Images", detailedMessage: "Check your network settings and try again", buttonMessage: "Ok")
}
}
}
I want to load the images into an array where I can use them later.
The line self.arrayOfWorkoutImages = [UIImage(data:imageData!)!] adds them to the array
var arrayOfWorkoutImages: [UIImage] = []
On trying to see whether the images are pulled (checking the print(self.arrayOfWorkoutImages) and print(self.arrayOfWorkoutImages.count) ) I get only ONE image counted and pulled. This is the function I am using that is linked to a button that does this.
#IBAction func addbuttonPressed(sender: AnyObject) {
self.loadAllObjects()
print(self.arrayOfWorkoutImages)
print(self.arrayOfWorkoutImages.count)
}
Any ideas on what I could be doing wrong. This is has been throwing errors at me for a couple of days now!! :(
Your code contains an error: for each object you re-assign to arrayOfWorkoutImages an array with the retrieved image.
func loadAllObjects(completion: () -> Void) {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .NetworkElseCache
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
discoveryQuery.findObjectsInBackgroundWithBlock { (objectsFound: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for var i = 0; i < objectsFound?.count; i++ {
if let imageFileFound = objectsFound![i].objectForKey("workoutImage") as? PFFile {
imageFileFound.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
if let data = imageData, image = UIImage(data: data) {
self.arrayOfWorkoutImages.append(image)
}
}
}
}
}
}
completion()
}
}

Uploading image to parse ios 9

I'm creating an app that allows the user to upload text and an image either taken from library or from the camera and uploads to parse. I get the text to upload no problem but it only will upload the image to parse 1 in 20 tries. Any thoughts? I've posted my code.
#IBAction func saveData(sender: AnyObject) {
var imageText = messageText.text
var uploadDate = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .MediumStyle
formatter.stringFromDate(uploadDate)
if messageText.text == nil {
print("Image not uploaded")
}else {
var posts = PFObject(className: "Memento")
posts["imageText"] = imageText
posts["uploadTime"] = uploadDate
posts["uploader"] = PFUser.currentUser()
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
var imageData = UIImagePNGRepresentation(self.imagePreview.image!)
var parseImageFile = PFFile(name: "uploaded_image.png", data: imageData!)
posts["imageFile"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
print("data uploaded")
self.performSegueWithIdentifier("saveHome", sender: self)
}else {
print(error)
}
})
} else {
print(error)
}
})
}
}
Make sure to save the image file to Parse as well as adding it to your posts object.
#IBAction func saveData(sender: AnyObject) {
var imageText = messageText.text
var uploadDate = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .MediumStyle
formatter.stringFromDate(uploadDate)
if messageText.text == nil {
print("Image not uploaded")
} else {
// Save the image
//var imageData = UIImagePNGRepresentation(self.imagePreview.image!)
//var parseImageFile = PFFile(name: "uploaded_image.png", data: imageData!)
var parseImageFile = PFFile(name: "uploaded_image.jpg", data: UIImageJPEGRepresentation(self.imagePreview.image!, 0.6)!)!
parseImageFile.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if (success) {
println("picture saved")
} else {
// Log details of the failure
println("Picture Save Error: \(error!) \(error!.userInfo)")
}
}
// Then save your posts object
var posts = PFObject(className: "Memento")
posts["imageText"] = imageText
posts["uploadTime"] = uploadDate
posts["uploader"] = PFUser.currentUser()
posts["imageFile"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
print("data uploaded")
self.performSegueWithIdentifier("saveHome", sender: self)
} else {
// Log details of the failure
println("Picture Save Error: \(error!) \(error!.userInfo)")
}
})
}
}

Better way to retrieve multiple images from Parse

Noob question here and I know my code below is very wrong but it works in that it retrieves the 3 images I need. However, I'd like to know a better way to retrieve multiple images from Parse.
Any help would be greatly appreciated!
func retrieveImage() {
var query = PFQuery(className: "Items")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let imageObjects = objects as! [PFObject]
for (index, object) in enumerate(imageObjects) {
let thumbnail1 = object["image1"] as! PFFile
let thumbnail2 = object["image2"] as! PFFile
let thumbnail3 = object["image3"] as! PFFile
thumbnail1.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.itemImages[index] = image
}
}
thumbnail2.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.itemImages2[index] = image
}
}
}
thumbnail3.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.itemImages3[index] = image
}
}
}
}
}
}
}
}
First the idea... we want to do an arbitrarily long list of asynch tasks, collect their results, and be notified on completion or error. We do this by parameterizing the task (in this case, the PFFiles whose contents are to be fetched are the parameters), and we use those parameters as a "to-do list".
A recursive function does the work, picking off the first item in the list, doing the asynch task, and then calling itself with the remainder of the list. An empty to-do list means we're done.
I've tried to translate the answer I referred to here into swift (literally learning the language line by line)....
func load(pfFiles: Array<PFFile>, var filling: Dictionary<PFFile, UIImage>, completion: (success: Bool) -> Void) {
completion(success: true)
var count = pfFiles.count
if (count == 0) {
return completion(success: true)
}
var file = pfFiles[0]
var remainder = Array(pfFiles[1..<count])
file.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
filling[file.name] = image
self.load(remainder, filling: filling, completion: completion)
}
} else {
completion(success: false)
}
}
}
Given this is my first attempt, I'll be a little shocked and delighted if it works, but the algorithm is sound, and the swift compiles and appears to match the idea I outlined. Here's how to call it...
var pfFiles: Array<PFFile>
for (index, object) in enumerate(imageObjects) {
pfFiles.append(object["image1"])
pfFiles.append(object["image2"])
pfFiles.append(object["image3"])
}
var filling: Dictionary<String, UIImage>
// call the function here
// in the completion assign filling to property
// anytime after, when you have a PFFile like someObject["image2"]
// you use its name to look it up the UIImage in the results dictionary
Let me know if that last bit is clear enough. As you can see, I ran out of steam on my swift translation and resorted to pseudo code.
I believe you can just do self.itemImages[index] = thumbnail1.getData()!
If it crashs, do : query.includeKey("image1")
NOTE:
If you afraid to block the main queue, open a new thread to do such thing

Resources