Below the code is retrieving from parse.com. The code is working properly but does not query my data in order. Can someone explain why?
func loadData(){
let findDataParse = PFQuery(className: "JobListing")
findDataParse.whereKey("user", equalTo: PFUser.currentUser()!)
findDataParse.orderByAscending("createdAt")
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!)
let offers = Information(objectIDParam: object.objectId!, titleOfProjectParam: object["TitleOfProject"] as! String, categoryParam: object["Category"] as! String, viewsParam: object["Views"] as! String, image1Param: listingImage1!, image2Param: listingImage2!, image3Param: listingImage3!)
self.arrayOfOffers.append(offers)
for interests in object["InterestsArray"] as! NSArray{
self.arrayOfInterests.append(interests as! String)
}
self.i++
self.tableView.reloadData()
}}}}}}}
Here's what I would do:
Create a mutableArray
Fetch all the items at the same time
When a request is finished add it's object to the mutableArray and check mutableArray.count == numberOfRequests
When all downloads are finished sort the mutableArray
This would be much faster + easy to understand what's going on.
Related
I am importing an image and string from parse and putting it within a cell, but it does not load into the view, when I go to another view and come back, it appears. Any reason why this is happening and how do I fix it? Notice I am calling this in the viewDidLoad.
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if(error == nil){
for object in objects!{
if let name = object["Animal"] as? PFObject{
self.animalname.append(name["Name"] as! String)
self.tableview.reloadData()
}
if let pic = object["Animal"]["Pic"] as? PFFile{
pic.getDataInBackgroundWithBlock({ (data: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: data!)
self.imagepro.append(image!)
}
})
self.tableview.reloadData()
}
}
}
Seems, you're reloading your table view, before the image downloads. Try this
if let pic = object["Animal"]["Pic"] as? PFFile{
pic.getDataInBackgroundWithBlock({ (data: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: data!)
self.imagepro.append(image!)
dispatch_async(dispatch_get_main_queue()) {
self.tableview.reloadData()
}
}
})
}
The code below works expectedly but I was wondering if I was retrieving multiple parse images the best way possible. What the code below does is retrieve 3 different PFFile columns by calling findObjectsInBackgroundWithBlock 3 separate times. Can this be condensed? If so, how can I better refine my function?
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
}}}}}}}
It would be better if you used an array column to store your files in Parse because then you could use a loop, but you can retrieve the images in parallel.
The code below shows this, but doesn't actually do anything with the images because it isn't clear what you are trying to do; your code in your question assigns all of the retrieved images to a single UIImageView, so only the last image that is retrieved is actually used.
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!)
}
}
}
I am appending the username column and the image column to two different arrays from parse. I am then putting them into the collection view. I am anticipating that the username in the nameArray corresponds to the imageArray, but majority of the time they are in the wrong order. How do I get them to append into the array in the right order? i.e. User 1 has picture 1, user 2 has picture 2. username array = [User 1, User 2]. image array = [picture 1, picture 2].
func getFriendPicandName(){
let imagequery = PFQuery(className: "_User")
imagequery.findObjectsInBackgroundWithBlock {( objects: [AnyObject]?, error: NSError?) -> Void in
// for object in objects!{
var user = PFUser.currentUser()
let relation = user!.relationForKey("Friendship")
relation.query()!.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects!{
let userPic = object["ProPic"] as! PFFile
userPic.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: imageData!)
self.arrayOfFriends.append(image!)
print(self.arrayOfFriends)
}
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
})
}
}
}
var query = PFQuery(className: "_User")
query.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]?, error: NSError?) -> Void in
var user = PFUser.currentUser()
let relations = user!.relationForKey("Friendship")
relations.query()!.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]?, error: NSError?) -> Void in
var objectIDs = objects as! [PFObject]
for i in 0...(objectIDs.count){
self.arrayOfFriendsNames.append(objectIDs[i].valueForKey("username") as! String)
print(self.arrayOfFriendsNames)
}
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
}
})
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrayOfFriendsNames.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: friendcellView = collectionView.dequeueReusableCellWithReuseIdentifier("friendcell", forIndexPath: indexPath) as! friendcellView
cell.friendname.text = arrayOfFriendsNames[indexPath.item]
cell.friendpic.image = arrayOfFriends[indexPath.item]
cell.friendpic.layer.cornerRadius = cell.friendpic.frame.size.width/2;
cell.friendpic.clipsToBounds = true
return cell
}
You should not call your query twice, I would imagine your for loop to look something like this:
for object in objects!{
let userPic = object["ProPic"] as! PFFile
userPic.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: imageData!)
self.arrayOfFriends.append(image!) // Add image here
print(self.arrayOfFriends)
}
self.arrayOfFriendsNames.append(object.valueForKey("username") as! String) // Add Name here
}
I don't know much about swift but I combined you both function into one...i hope it will help you...
func getFriendPic(){
let imagequery = PFQuery(className: "_User")
imagequery.findObjectsInBackgroundWithBlock {( objects: [AnyObject]?, error: NSError?) -> Void in
// for object in objects!{
var user = PFUser.currentUser()
let relation = user!.relationForKey("Friendship")
relation.query()!.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
var objectIDs = objects as! [PFObject]
for i in 0...(objectIDs.count){
self.arrayOfFriendsNames.append(objectIDs[i].valueForKey("username") as! String)
print(self.arrayOfFriendsNames)
}
for object in objects!{
let userPic = object["ProPic"] as! PFFile
userPic.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: imageData!)
self.arrayOfFriends.append(image!)
print(self.arrayOfFriends)
}
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
})
}
}
}
}
I am attempting to fetch data from parse.com into my custom cell which is full of strings and images. I believe I am either retrieving my PFFile incorrectly from parse.com or I am retrieving the PFFile correctly but converting the file to UIImage improperly. The error i am receiving is going on within the loadData() function. It reads as follows: could not find an overload for 'init' that accepts the supplied arguments
Information
//Used to set custom cell
class Information {
var partyName = ""
var promoterName = ""
var partyCost = ""
var flyerImage: UIImage
var promoterImage: UIImage
init(partyName: String, promoterName: String, partyCost: String, flyerImage: UIImage, promoterImage: UIImage) {
self.partyName = partyName
self.promoterName = promoterName
self.partyCost = partyCost
self.flyerImage = flyerImage
self.promoterImage = promoterImage
}
}
Parse fetch function
func loadData() {
var findDataParse:PFQuery = PFQuery(className: "flyerDataFetch")
findDataParse.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
for object in objects! {
var eventImage0 : UIImage
var eventImage10 : UIImage
let userImageFile = object["partyFlyerImage"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let eventImage = UIImage(data:imageData!)
eventImage0 = eventImage!
}
}
let userImageFile1 = object["partyPromoterImage"] as! PFFile
userImageFile1.getDataInBackgroundWithBlock {
(imageData1: NSData?, error1: NSError?) -> Void in
if error1 == nil {
let eventImage1 = UIImage(data:imageData1!)
eventImage10 = eventImage1!
}
}
//Error below
var party1 = Information(partyName: (object["partyName"] as? String)!, promoterName: (object["partyPromoterName"] as? String)!,partyCost: (object["partyCost"] as? String)!, flyerImage: UIImage(data: eventImage0)!, promoterImage: UIImage(data: eventImage10)!)
self.arrayOfParties.append(party1)
}
}
self.tableView.reloadData()
}
}
You are fetching data from Parse in background, but processing on main thread. Try this:
func loadData() {
var findDataParse:PFQuery = PFQuery(className: "flyerDataFetch")
findDataParse.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
for object in objects! {
var eventImage0 : UIImage
var eventImage10 : UIImage
let userImageFile = object["partyFlyerImage"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let eventImage = UIImage(data:imageData!)
eventImage0 = eventImage!
let userImageFile1 = object["partyPromoterImage"] as! PFFile
userImageFile1.getDataInBackgroundWithBlock {
(imageData1: NSData?, error1: NSError?) -> Void in
if error1 == nil {
let eventImage1 = UIImage(data:imageData1!)
eventImage10 = eventImage1!
var party1 = Information(partyName: (object["partyName"] as? String)!, promoterName: (object["partyPromoterName"] as? String)!, partyCost: (object["partyCost"] as? String)!, flyerImage: UIImage(data: eventImage0)!, promoterImage: UIImage(data: eventImage10)!)
self.arrayOfParties.append(party1)
}
}
}
}
}
}
self.tableView.reloadData()
}
}
Your fetching your images Asynchronously and creating your Information cell Synchronously. So when you create the cell, the images are likely not loaded and your are in effect sending nil to the constructor for the cell.
In the following code you are retrieving the image data async:
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let eventImage = UIImage(data:imageData!)
eventImage0 = eventImage!
}
}
So when you assign the image data to eventImage0, the call to the Information cell initializer has probably already happened.
You need to modify the code to instead of passing the image into the cell view initializer, allow you to access the UIImageview from the Information cell, so that when the background image loads complete you can simply set the loaded image into that UI/PF/ImageView.
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)
}
}
}
}
}
}
}