I'm trying to retrieve images from Parse as PFFiles but the order in which they are returned changes every time. I found another question/answer that addresses this problem but it's in Obj-C and after an hour, I cannot translate a working solution in Swift.
Here's the original thread:
Parse PFFile download order iOS
And here's my code:
func retrieveItemImage() {
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 object in imageObjects {
let thumbnail = object["image1"] as! PFFile
thumbnail.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.images.append(image)
self.theTableView.reloadData()
}
}
}
}
}
self.theTableView.reloadData()
}
}
I would make it that way:
var images = [Int: UIImage]()
Make it a dictionary, then you get an optional result of subscript and never have an array out of range exception.
Then I would rewrite the part of your code as:
for (index, object) in enumerate(imageObjects) {
let thumbnail = object["image1"] as! PFFile
thumbnail.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.images[index] = image
You never know the order of async operations completion, but your images will be in specified order, or nil in dictionary. You should also correct your tableView methods to check it for nil. Also, in my opinion, reloading the whole table after each image loading is ineffective.
Related
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 {
}
Ok, I have looked at questions like How do you access an object's fields from a Parse query result in Swift? but the answer is not working in Swift 3. With the following trying to get an image from the first PFObject in Parse I get the error:
Cannot convert value type NSData, NSError -> Void to expected
PFDataResultBlock ?
var query = PFQuery(className: PARSE_CLASS!)
query.order(byDescending: "createdAt")
query.findObjectsInBackground {
(objects, error) -> Void in
if error == nil {
//print(objects?.first?["testTxt"] as! NSString)
//print(objects?.first?["testImg"] as! PFFile)
let thumbnail = objects?.first?["testImg"] as! PFFile
thumbnail.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
//get image here
}
}
}
}
I have tried changing the type and everything. How can I store an image from Parse in recent Swift?
You can try this:
if let validObjects = objects {
for object in validObjects {
let thumbnail = object["testImg"] as? PFFile
thumbnail?.getDataInBackground (block: { (data, error) -> Void in
//read image here
}
}
}
So I have been trying to retrieve an image from Parse since yesterday and I am very confused. I read similar questions and examples but all of them were people saving some image first, then retrieving it. What I want to do is simply retrieve an image that I manually uploaded to parse, I have been trying with this:
//Retrieving image from parse
var object = PFObject(className:"ClassImage")
let getParseImg = object["image"] as! PFFile
getParseImg.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if (error == nil){
if let imageData = imageData{
println("Retrieving Image")
let img = UIImage(data:imageData)
self.imageView.image = img
}
}
}
In line two, it throws a "unexpectedly found nil while unwrapping an Optional value", I already tried "if let getParseImg", then it throws another error, in the end the line ended up looking like this:
if let getParseImg = object["image"] as? PFFile{
So after that, everything goes fine and compiles but it doesn't do absolutely anything, it does not get and display the image and it doesn't even print "Retrieving Image", any ideas how can I solve this, I am new to Parse so still getting familiarized with it.
Thanks in advance!
You need to run a query. Also, I used a dictionary called imagesDict in order to ensure your photos are returned in the correct order.
var query = PFQuery(className: "ClassImage")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let imageObjects = objects as! [PFObject]
for (index, object) in enumerate(imageObjects) {
let thumbnail = object["image"] as! PFFile
thumbnail.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let image = UIImage(data: imageData!) {
self.imagesDict[index] = image
self.theTableView.reloadData()
}
}
}
}
}
}
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!
I have created a var userImages = [PFFile]() and have appended the respective user images from Parse via a user query and self.userImages.append(user["imageFile"] as! PFFile). This works fine. However, when I try to set the image of the user via
userImages.getDataInBackGroundWithBlock{ (data, error) -> Void in ...
I'm receiving the following error: **'[(PFFile)]' does not have a member named 'getDataInBackGroundWithBlock'**
Why doesn't this work and what might be a solution for this issue?
Thank you for the help!!
You are trying to call getDataInBackGroundWithBlock in a array try to use"
userImages.last?.getDataInBackGroundWithBlock{...}
or you can save it in a variable and use the new PFFIle to retrieve the image
let userImage = user["imageFile"] as! PFFile
userImage.getDataInBackGroundWithBlock{...}
or access it directly using:
(user["imageFile"] as! PFFile).getDataInBackGroundWithBlock{...}
The role process being:
self.userImages.append(user["imageFile"] as! PFFile) //This is just a reference to download the image
userImages.last?.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData) // this is the final image
}
}
}