Hi I have a PFQuery where I am retrieving map images and I need to sort them so that i can retrieve the correct image in my code. This is currently my code:
func retrieveImages() {
self.imageArray = [UIImage]()
var query = PFQuery(className:"Maps")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
self.objectNames.append(object["Name"]!)
let userImageFile = object["imageFile"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if imageData != nil {
let imageData = imageData
var image = UIImage(data:imageData!)
if image != nil {
self.imageArray.append(image!)
}
}
}
}
}
}
}
}
}
I tried to sort the query by using the orderByDescending function but when i run the code only the names of the objects are sorted and the images themselves are not. There also seems to be no pattern in how the images are sorted because each time I run this code the order of the images are different. Any advice or insight would be appreciated.
Related
I am new to coding.
Trying to append images from Parse to a [UIImage] but get the error "Cannot convert value of type PFFileObject to expected argument type UIImage.
How can I convert the PFFile to a UIImage?
#Published var profileManageImages = [UIImage]()
ForEach(uploadMedia.profileManageImages, id: \.self) { picture in
Image(picture)
func refreshSideScroll() {
let currentUser = PFUser.current()
let query = PFQuery(className: "Photos")
query.whereKey("uploadedBy", equalTo: currentUser!)
query.limit = 8
query.findObjectsInBackground(block: { (objects: [PFObject]?, error: Error?) in
if error == nil {
for images in objects!{
self.profileManageImages.append(images["image"] as! PFFileObject)
}
}
})
}
You need still to fetch data of image from PFFileObject, like
query.findObjectsInBackground(block: { (objects: [PFObject]?, error: Error?) in
if error == nil, let objects = objects {
for object in objects {
if let file = object["image"] as? PFFileObject {
file.getDataInBackgroundWithBlock{(data: NSData?, error: NSError?) in
if error == nil, let data = data, let image = UIImage(data: data) {
DispatchQueue.main.async {
self.profileManageImages.append(image)
}
}
}
}
}
})
Below is an example of how i would typically retrieve images from my Parse.com. I have now run into the situation where i would like to retrieve 20+ images from Parse but i am looking for a more efficient way to do so. Please can someone explain how to implement this in code and how i should store the 20+ PFFiles in Parse?
func loadData(){
let findDataParse = PFQuery(className: "JobListing")
findDataParse.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
for object in objects! {
let userImageFile = object["ImageOne"] as! PFFile
let userImageFile1 = object["ImageTwo"] as! PFFile
let userImageFile2 = object["ImageThree"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
let listingImage1 = UIImage(data:imageData!)
userImageFile1.getDataInBackgroundWithBlock {
(imageData1: NSData?, error1: NSError?) -> Void in
let listingImage2 = UIImage(data:imageData1!)
userImageFile2.getDataInBackgroundWithBlock {
(imageData2: NSData?, error1: NSError?) -> Void in
let listingImage3 = UIImage(data:imageData2!)
self.flyerImageLarge1.image = listingImage1
self.flyerImageLarge2.image = listingImage2
self.flyerImageLarge3.image = listingImage3
}}}}}}}
You can use ParseUI for cleaner and more efficient code.
To do so, add the ParseUI framework.
Then, click the image and change the "class" to PFImageView.
You can see this here.
Once you do that, you can easily set the PFImageView's image:
if let myServerImage = object.valueForKey("imageFromUser") as? PFFile {
self.myImage.file = myServerImage
self.myImage.loadInBackground()
}
Where myServerImage is the image you are retrieving from the Parse server and myImage is the image in your storyboard.
In your case it will be something like this:
func loadData(){
let findDataParse = PFQuery(className: "JobListing")
findDataParse.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
if let myServerImage = object.valueForKey("ImageOne") as? PFFile {
self.flyerImageLarge1.file = myServerImage
self.flyerImageLarge1.loadInBackground()
}
if let myServerImage = object.valueForKey("ImageTwo") as? PFFile {
self.flyerImageLarge2.file = myServerImage
self.flyerImageLarge2.loadInBackground()
}
if let myServerImage = object.valueForKey("ImageThree") as? PFFile {
self.flyerImageLarge3.file = myServerImage
self.flyerImageLarge3.loadInBackground()
}
}
}
I recommend adding the if let statement so that you don't get an error when an image doesn't exist.
Please forgive me if what I am saying is obvious or already considered. I'm not completely familiar with what you are doing, but it looks applicable.
Assuming you are not using it already, you will need to use a recursive function. Basically, a function that calls itself until the end condition.
I'm not familiar with your code so I'll demonstrate with a simple example in JavaScript:
/* A "public" function that your program will call */
function getStuff(total)
{
//quick positive check
if (total > 0)
{
//start and pass in an empty array
return _getStuffRecursion(total, []);
}
else
{
//total is not positive, return empty array
return [];
}
}
/* A "private" function that will do the recursion */
function _getStuffRecursion(total, resultsArray)
{
//do work this is where you would call your function that does the work.
var someResource = Math.random();
//add work to the array collected so far
resultsArray.push(someResource);
//change count
var newTotal = total - 1;
//check condition
if (newTotal > 0)
{
//recursive condition, go to the next level down and pass in what is collected so far
return _getStuffRecursion(newTotal, resultsArray)
}
else
{
//end condition met, just return the array with everything collected from the upper levels
return resultsArray;
}
}
/* Start */
//get started by calling the "public" function
var results = getStuff(20);
//print it to console
console.log(results);
If this solution works, I'm sure you can adapt it to Parse.
I am getting a fatal error: unexpectedly found nil while unwrapping an optional value. I get this error after the code gets to self.imageArray.append(image!) from this code:
func retrieveImages()
{
var query = PFQuery(className: "Maps")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil && objects != nil {
let objects = objects as! [PFObject]
for object in objects {
let imageFile = object["imageFile"] as! PFFile
imageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if imageData != nil {
let imageData:NSData! = imageData
let image = UIImage(data: imageData)
self.imageArray.append(image!)
}
}
}
}
}
}
}
I have checked each line of code and image does not become nil until i try to append it to the end of the imageArray.
like previous mentioned, you are reassigning a lot of variables. Try you if-let statements on the optional variables like this:
func retrieveImages(){
var query = PFQuery(className: "Maps")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) in
if let objects = objects as? [PFObject] where error == nil {
for object in objects {
if let imageFile = object["imageFile"] as? PFFile {
imageFile.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) in
if let imageData = imageData, let image = UIImage(data: imageData) {
self.imageArray.append(image)
}
}
}
}
}
}
}
I am trying to display an image from parse using swift. This is my code:
var query = PFQuery(className: "Maps")
query.getObjectInBackgroundWithId("1234asdf3456") {
(object: PFObject?, error: NSError?) -> Void in
if error == nil
{
println(object)
var objectAsPF = object as PFObject!
let file = objectAsPF["imageFile"] as! PFFile
file.getDataInBackgroundWithBlock {
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let map:UIImage = UIImage(data: imageData)!
self.MapView.image = map
println("success")
}
}
}
}
else
{
println(error)
}
}
I set a breakpoint at println("success") and i checked the variable values and everything is fine until i try to convert imageData to UIImage. Any tips?
Use this code to retrieve images from parse then convert it from a PFFile to a UIImage...
var query = PFQuery(className:"Maps")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
self.scored = objects!.count
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
let userImageFile = object["imageFile"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
if image != nil {
self.imageArray.append(image!)
}
}
}
}
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
dispatch_async(dispatch_get_main_queue()) {
println("Finished Loading Image")
}
I have an item Object which has a relation class which contain several images related to the item. The problem is I'm trying to add these images to an array so first inside the loop I'm adding them to one array and after the loop I'm adding them to the image Array and then when the loop is completed I want to reload table View. At the moment it seems like
Self.imageArray.addObject(imageDic)
is being called before the loop and therefor nothing is added to the array.
How can I do this?
var relation = itemObject.relationForKey("file") as PFRelation
var imageQuery = relation.query() as PFQuery
imageQuery.findObjectsInBackgroundWithBlock { (imageObj: [AnyObject]!, error1: NSError!) -> Void in
if error1 == nil {
var imageDic = NSMutableArray()
for obj in imageObj {
var imageObject = obj as PFObject
var thumbnail = imageObject.objectForKey("file") as PFFile
thumbnail.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
let image = UIImage(data:imageData)
imageDic.addObject(image)
}
}
}
self.imageArray?.addObject(imageDic)
println(self.imageArray?.count)
}
}
self.tableView?.reloadData()
}
See the block is called afterwards and your self.tableView?.reloadData() would be called before anything is added to it.
So I made cahnges in your code as below:-
var relation = itemObject.relationForKey("file") as PFRelation
var imageQuery = relation.query() as PFQuery
imageQuery.findObjectsInBackgroundWithBlock { (imageObj: [AnyObject]!, error1: NSError!) -> Void in
if error1 == nil {
var imageDic = NSMutableArray()
for obj in imageObj {
var imageObject = obj as PFObject
var thumbnail = imageObject.objectForKey("file") as PFFile
thumbnail.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
let image = UIImage(data:imageData)
// imageDic.addObject(image) //No need of this array.
self.imageArray?.addObject(imageDic)
println(self.imageArray?.count) //simply add object into this array.
}
}
}
self.tableView?.reload()
}
}
}