How to Reload Data Properly When Retrieving Objects from Parse

Not able to reload data properly when retrieving objects from Parse

I've had this problem before and fixed it by embedding a button in each cell. Inside your UITableView you should try embedding each cell with a UIButton.

First make a custom UITableViewCell in a separate file. Then drag and make an IBOutlet for your UIButton inside your custom cell.

class MyCustomCell: UITableViewCell{
@IBOutlet weak var followButton: UIButton!
var isFollowing:Bool = false
//Declare other cell attributes here like picture, name, gender
// ......
}

When you query and gather the data for your cells, you can store them in an array in your UITableViewController. For example, var myCellArray = [MyCustomCell](). Then your UITableViewController will look something like this:

var myCellArray = [userListTableViewCell]()

override func viewDidLoad(){
super.viewDidLoad()

var userQuery = PFUser.query()
userQuery.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in

if let usersArray = objects as! [PFUser] {

self.myCellArray.removeAll(keepCapacity: false)

for user in usersArray {

if let user = object as? PFUser {
if user.objectId != PFUser.currentUser()?.objectId {
var myCell = userListTableViewCell()
myCell.userID = user.objectId
myCell.username = user["fullName"] as! String
myCell.gender = user["gender"] as! String

var userPicture = user["profilePicure"] as? PFFile
var image = UIImage(data:userPicture!.getData()!)
myCell.displayPicture.image = image

myCellArray.append(myCell)
self.tableView.reloadData()

}
}
}
}
})
}

override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
myCellArray.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

var cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier") as! userListTableViewCell

//Edit the storyboard labels for each cell:
cell.username.text = myCellArray[indexPath.row].username
// etc....

//Embed a button with each cell
cell.followButton.layer.setValue(indexPath.row, forKey: "index")
cell.followButton.addTarget(self, action: "followButtonTapped:", for ControlEvents: UIControlEvents.TouchUpInside)

if (myCellArray[indexPath.row].isFollowing == false){
cell.followButton.setTitle("Follow", forState: .Normal)
}else{
cell.followButton.setTitle("Unfollow", forState: .Normal)
}
return cell
}

func followButtonTapped(sender: UIButton){
let cellIndex : Int = (sender.layer.valueForKey("index")) as! Int
//You now have the index of the cell whose play button was pressed so you can do something like
if (myCellArray[cellIndex].isFollowing == false){
myCellArray[cellIndex] = true
}else{
myCellArray[cellIndex] = false
}
self.tableView.reloadData()
}

Where to Reload UITableView Data after parse query

The part that complicates the code is the need to fetch images using the objects returned by the query. The simplest solution is to omit the image fetching from the query completion handler.

  1. Instead, loop the returned objects, building the arrays (there's room for improvement here, too, but just sticking with the crash part of your problem for now). In the _bookImageData array, don't try to keep images, instead keep the PFFile for each object...

    // in the loop of objects, omit getDataInBackground and just do...
    [_bookImageData addObject:object[@"image"]];
  2. The answer to the stated question -- where to reload the table -- is after the loop that builds the table datasource.

    for (PFObject *object in objects) {
    // code to build all of the arrays, omitting getDataInBackground
    // ...
    }
    [self.tableView reloadData];
  3. In your table view cell, replace the image view with a PFImageView, because it can take care of fetching the image data for you (and other useful stuff like cacheing it). Your cellForRowAtIndexPath: will then look like this...

    // bookImageLabel must be a PFImageView
    // remember, we put the PFFile for each object into the _bookImageData array
    cell.bookImageLabel.file = _bookImageData[indexPath.row];
    [cell.bookImageLabel loadInBackground];

Swift why when Retrieving data from Parse I have to press button twice to load data in tableview

Your call to self.tableView.reloadData() is in the wrong place and it's being called from the wrong queue. You need to call it on the main queue and it needs to be called inside the query completion handler after you update the data model.

query.findObjectsInBackground(block: { (objects : [PFObject]?, error: Error?) -> Void in
if error == nil {
for object in objects! {
if let userPicture = object.value(forKey: "photo") {
let userPicture = object.value(forKey: "photo")! as! PFFile
userPicture.getDataInBackground({ (imageData: Data?, error: Error?) -> Void in
let image = UIImage(data: imageData!)
if image != nil {
self.Saveddata.append(image!)
}
})
}
}
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
})

Retrieving data objects from localstorage and reload them into array

You've added that you are calling from onload, and,

in your code you are loading into students.

add to the beginning of your code:

var students;.

Note: Some Objects need special handling.

For example: Date:

var date = new Date();
localStorage.date = JSON.stringify(date);
date = new Date(JSON.parse(localStorage.date));

Answer before additional information:

key is a method of localStorage.

Don't use it.

Use students instead, for example.

Storage.key()

(This is assuming that you call the functions)

var students = [{name: "Petrina", age: "20"}];
function saveToLocalStorage(key, value){
localStorage.setItem(key, JSON.stringify(value));
console.log("Saved to LocalStorage");
}
function loadFromLocalStorage(key){
console.log("Loaded from LocalStorage");
return JSON.parse(localStorage.getItem(key));
}
console.log("students: "+students);
saveToLocalStorage("stu", students);
var st2=loadFromLocalStorage("stu");
console.log("st2: "+st2);
  • cannot be run in a snippet: sandboxed, no access to localStorage - cross origin.

Difficulty retrieving Parse Object Field Values

You should refresh your tableview with this method;

self.tableView.reloadData()

You can put this code after your findObjectsInBackgroundWithBlock callback closure in your case;

projectRetrieval.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {

//Append the productNames array with retrieved projectnames
self.productNames.append(object["projectname"] as! String)

// This line successfully prints the array of product Names retrieved.
print("Projectnames: \(self.productNames)")

}
}
self.tableView.reloadData()
})


Related Topics



Leave a reply



Submit