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()
}
}
}
Related
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()
}
}
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.
So I am saving some objects to the localDatastore using parse.
//Pin the objects here!!
var imageObject = PFObject(className: "img")
imageObject["theFile"] = imageFile
imageObject.pinInBackgroundWithBlock({ (success, error) -> Void in
if error == nil {
imageObject.saveEventually()
println("object pinned in background")
} else {
println(error)
}
})
Then in the viewDidLoad I am querying the objects and appending them into an array of PFFile's
var query = PFQuery(className: "img")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil{
var objects : AnyObject = objects as! AnyObject
for object in objects as! [AnyObject]{
self.testImages.append(object["theFile"] as! PFFile)
}
} else {
println(error)
}
}
With this array now containing data. I am trying to insert the images into the tableView
if testImages.count >= 1{
testImages[indexPath.row].getDataInBackgroundWithBlock({ (imageData, error) -> Void in
if error == nil{
//The app crashes here ~ fatal error: unexpectedly found nil while unwrapping an Optional value
cell.theImage.image = UIImage(data: imageData!)
} else {
println(error)
}
})
}
Because you are using a tableview, I think the best way is to download all the images from Parse and save it to an array. Then in the cellForRowAtPath method then you assign each index of that array to the cell.imageView.image
var query = PFQuery(className:"img")
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objects = objects as? [PFObject]
{
for one in objects
{
var pictureImage = one["theFile"] as! PFFile
pictureImage.getDataInBackgroundWithBlock({ (dataToget:NSData?, error:NSError?) -> Void in
if error == nil
{
if let Image = UIImage(data: dataToget)
{
// save the image to array
// reload the tableview
}
}
})
}
}
}
}
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.
I'm retrieving set of images from Parse, using the following code using Swift.
var imageResources : Array<UIImage> = []
override func viewDidLoad(){
super.viewDidLoad()
self.loadImages()
}
func loadImages(){
var query = PFQuery(className: "Images")
query.orderByDescending("objectId")
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
for object : PFObject! in objects as [PFObject] {
var thumbNail = PFFile()
thumbNail = object["image"] as PFFile
println("thumNail \(thumbNail)")
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) in
if (error == nil) {
let image : UIImage = UIImage(data:imageData)
//image object implementation
self.imageResources.append(image)
}
})//getDataInBackgroundWithBlock - end
}//for - end
}
else{
println("Error in retrieving \(error)")
}
})//findObjectsInBackgroundWithblock - end
}
My Parse Class detail
class name - Images
When I run this function, it's getting crashed without a message in the console.
Note: I'm able to get the collection of PFFile objects in the callback.
I've replaced
"thumbNail.getDataInBackgroundWithBlock({...." block with the synchronous function call thumbNail.getData() like
"var imageData= thumbNail.getData()
var image = UIImage(data:imageData)"
Then the error says
Warning: A long-running operation is being executed on the main thread.
Break on warnBlockingOperationOnMainThread() to debug.
So, I reverted to thumbNail.getDataInBackGroundWithBloack({...
But now, there is no error display in the console, as it happens before. Is there anything wrong in my approach please let me know.
Any help would be appreciated...!
I managed to recreate the error, which seems to be some kind of memory leak / zombie on a PFObject. I'm not sure exactly why, but refactoring your code in the following manner got rid of the error in my case:
func loadImages() {
var query = PFQuery(className: "Images")
query.orderByDescending("objectId")
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
self.getImageData(objects as [PFObject])
}
else{
println("Error in retrieving \(error)")
}
})//findObjectsInBackgroundWithblock - end
}
func getImageData(objects: [PFObject]) {
for object in objects {
let thumbNail = object["image"] as PFFile
println(thumbNail)
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
let image = UIImage(data:imageData)
//image object implementation
self.imageResources.append(image)
println(image)
}
})//getDataInBackgroundWithBlock - end
}//for - end
}
EDIT: Incidentally, this also works:
func loadImages() {
var query = PFQuery(className: "Images")
query.orderByDescending("objectId")
query.findObjectsInBackgroundWithBlock ({(objects:[AnyObject]!, error: NSError!) in
if(error == nil){
let imageObjects = objects as [PFObject]
for object in objects {
let thumbNail = object["image"] as PFFile
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
let image = UIImage(data:imageData)
//image object implementation
self.imageResources.append(image)
println(image)
}
})//getDataInBackgroundWithBlock - end
}//for - end
}
else{
println("Error in retrieving \(error)")
}
})//findObjectsInBackgroundWithblock - end
}
This would indicate that the error was due to the following line:
for object : PFObject! in objects as [PFObject] {
Rewriting that line as follows:
for object : PFObject in objects as [PFObject] {
Also removes the error. So the reason for this error seems to be that that you told the program to unwrap something that wasn't an optional.