Retrieve data of users from parse to show in tableview with swift - ios

This is my code in swift
class UserViewController: UITableViewController {
var userArray: [String] = []
#IBOutlet weak var friendListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
retrieveMessages()
}
func retrieveMessages() {
var userArray: [String] = []
var query:PFQuery = PFQuery(className: "User")
var currentUser = query.whereKey("username", equalTo: PFUser.currentUser())
currentUser.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
for object in objects! {
let username:String? = (object as PFObject)["Friends"] as? String
if username != nil {
self.userArray.append(username!)
}
}
}
self.friendListTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return userArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Update - replace as with as!
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = userArray[indexPath.row]
return cell
}
This is my user's table https://www.dropbox.com/s/6xp48v3yn0l2hje/Screen%20Shot%202015-06-03%20at%202.10.13%20PM.png?dl=0
This is my current user's friend list in Parse Relation https://www.dropbox.com/s/pd8mt8sf35u1m0v/Screen%20Shot%202015-06-03%20at%202.10.55%20PM.png?dl=0
I've saved current user's friend list with PFRelation in class "User" in column "Friends" and I want to retrieve current user's friend list to show it in tableview but The problem is I can't update tableview to show current user's friend list, It's empty and there's no user list in tableview at all.
Is my code correct for this method? If not please help me correct this code.
Thank you!

You are updating the table before you receive the list from Parse, try this:
func retrieveMessages() {
var userArray: [String] = []
var query:PFQuery = PFQuery(className: "User")
var currentUser = query.whereKey("username", equalTo: PFUser.currentUser())
currentUser.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
for object in objects! {
let username:String? = (object as PFObject)["Friends"] as? String
if username != nil {
self.userArray.append(username!)
}
}
self.friendListTableView.reloadData()
}
}
The only difference is that I move the reloadData function inside the completition block so it will happen after the data is returned from parse

You have to call reloadData from inside the findObjectsInBackgroundWithBlock block.
Right now you are calling reloadData before your data is fetched.

Related

Cell images are showing out of order, why is this happening?

I'm building out a image feed that includes an image followed by a username label inside of a table view. For some reason, the cell images don't match the correct usernames. It almost seems that the images are downloaded in a different order than the usernames, but that can't be the case. Please help!
EDIT: After doing some console logging, I see that the images are downloaded and appended to the images array, in an different order than the usernames. BUT I don't know why, nor how to fix it.
import UIKit
class TrendingChallengeTableViewCell: UITableViewCell {
#IBOutlet var postImage: UIImageView!
#IBOutlet var postComment: UILabel!
override func prepareForReuse() {
super.prepareForReuse()
self.postImage.image = nil
self.postComment.text = ""
}
}
import UIKit
import Parse
var pressedChallenge: String?
class TrendingChallengeTableViewController: UITableViewController {
var images = [PFFile]()
var usernames = [String]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true
let query = PFQuery(className: "Post")
query.whereKey("imageComment", equalTo: pressedChallenge!)
query.findObjectsInBackgroundWithBlock { (object, error) -> Void in
self.usernames.removeAll(keepCapacity: true)
self.images.removeAll(keepCapacity: true)
if let object = object {
for images in object {
self.images.append(images["imageFile"] as! PFFile)
let userQuery = PFUser.query()
userQuery?.whereKey("_id", equalTo: images["userId"])
userQuery?.findObjectsInBackgroundWithBlock({ (object, error) -> Void in
if let object = object {
for user in object {
self.usernames.append(user["username"] as! String)
self.tableView.reloadData()
}
}
})
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let trendCell = tableView.dequeueReusableCellWithIdentifier("trendingCell", forIndexPath: indexPath) as! TrendingChallengeTableViewCell
trendCell.postComment.text = "\(usernames[indexPath.row]) completed the \(pressedChallenge!) challenge!"
images[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
trendCell.postImage.image = downloadedImage
}
}
return trendCell
}
}
Try telling both your queries to sort in a specific way before fetching the objects, ie:
let query = PFQuery(className: "Post")
query.whereKey("imageComment", equalTo: pressedChallenge!)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (object, error) -> Void in
//etc
}
Do this for the second query as well.

Data retrieval using Parse in Swift 2

I did this for fetching data and showing it in a table view
but it's not showing anything.
I used this code:
import UIKit
import Parse
import Bolts
class Parsedata: UIViewController, UITableViewDelegate, UITableViewDataSource {
//#IBOutlet var NTableView: UITableView!
#IBOutlet var NTableView: UITableView!
var NArray:[String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.NTableView.delegate = self
self.NTableView.dataSource = self
// retrieve notification from parse
self.RetrieveN()
NSLog("Done with it")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func RetrieveN () {
//create a pfquery
var query:PFQuery = PFQuery(className: "Notification")
//call findobject in background
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
//clear the Narray
self.NArray = [String]()
//loop through the objects array
for Nobject in objects!{
//retrieve the text column value of each PFobject
let Ntext:String? = (Nobject as! PFObject) ["Text"] as? String
// assign it into your Narray
if Ntext != nil {
self.NArray.append(Ntext!)
}
}
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) Notifications.")}
//reload the table view
self.NTableView.reloadData()
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.NTableView.dequeueReusableCellWithIdentifier("NCell") as UITableViewCell?
cell?.textLabel?.text = self.NArray[indexPath.row]
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return NArray.count
}
}
It's working fine because it's showing that 3 objects were retrieved on the LOG container.
Unless you have more code than what's posted here, you also need to implement numberOfSectionsInTableView and return 1
I have just learnt how to do this myself, this is how you can load data from parse and save it as a NSMutableArray then use that data to populate your table view.
let NArray : NSMutableArray = NSMutableArray()
then you can use your query you made with
var query:PFQuery = PFQuery(className: "Notification")
query.findObjectsInBackgroundWithBlock( { (AnyObject objects, NSError error) in
if error == nil {
self.NArray = NSMutableArray(array: objects!)
self.NTableView.reloadData()
} else {
print(error?.localisedDescription)
})
this will load all your content into the variable NArray, which you can then use in your tableView function with indexPath. That line of code inside your tableView cellForRowAtIndexPath would be
cell?.textLabel?.text = self.NArray[indexPath.row] //you may have to cast this as? String
Like i said this is how i am loading my data, i am using this to load PFUser usernames, profile pictures etc and displaying them in a custom table view cell.
You may have to slightly tweak these methods but the base methods are there

Tableview list is empty causes by findObjectInBackgroundWithBlock return nil

These are my code in swift
This is the code of retrieving the current user's friend list object with parse
class UserViewController: UITableViewController {
var userArray: NSMutableArray = []
#IBOutlet weak var friendListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
retrieveMessages()
}
func retrieveMessages() {
var query = PFUser.query()
if let username = PFUser.currentUser().username {
query.whereKey("username", equalTo: username)
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
for object in objects! {
let usernames:String? = (object as PFObject)["Friends"] as? String
println(usernames) // It prints "nil"
if usernames != nil {
self.userArray.addObject(usernames!)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.friendListTableView.reloadData()
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return userArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Update - replace as with as!
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = userArray[indexPath.row] as? String
return cell
}
and this is the code of saving current user's friend when the current user add them via username with parse
class addUserViewController: UIViewController {
#IBOutlet weak var usernameTextField: UITextField!
#IBAction func addUser(sender: AnyObject) {
var query = PFUser.query()
query.whereKey("username", equalTo: usernameTextField.text)
println("Pass")
query.getFirstObjectInBackgroundWithBlock{ (object:PFObject!, error: NSError!) -> Void in
if error == nil {
let currentUser = PFUser.currentUser()
let friendList = currentUser.relationForKey("Friends")
var addFriend = object
if addFriend != nil {
friendList.addObject(addFriend)
println("added")
}
PFUser.currentUser().saveInBackgroundWithBlock{
(succeeded: Bool!, error: NSError!) in
if error != nil {
println("Error")
}
else {
println("saved")
}
}
}
}
}
I want to retrieve current user's friend list to show it in tableview but the tableview won't update to show current user's friend list, It's empty and there's no user list in tableview at all. I've tried to fix it and check if method get any object.
The problem is when I use println(usernames) ,It prints "nil" which the method doesn't get any object at all. First I use username as NSArray then I changed it into NSMutableArray and it doesn't have append method like NSArray did so I did a research and add the "add object" line of code in it and change a few things. Right now I'm not sure at all what's wrong with my code and I've been stuck at this for a week now, If my code's wrong somehow can you please guide me where? or fix it would be great. Any help is appreciated
here's the screenshot of my User's class table in parse
https://www.dropbox.com/s/6xp48v3yn0l2hje/Screen%20Shot%202015-06-03%20at%202.10.13%20PM.png?dl=0
here's the screenshot of my current user's friend in parse which is saveāļ with PFRelation method as seen above
https://www.dropbox.com/s/pd8mt8sf35u1m0v/Screen%20Shot%202015-06-03%20at%202.10.55%20PM.png?dl=0
Thanks in advance!!

User's friend list tableview is empty and parse query did not return any data

This is my code in swift
class UserViewController: UITableViewController {
var userArray: NSMutableArray = []
#IBOutlet weak var friendListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
retrieveMessages()
}
func retrieveMessages() {
var query = PFUser.query()
if let username = PFUser.currentUser().username {
query.whereKey("username", equalTo: username)
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
for object in objects! {
let usernames:String? = (object as PFObject)["Friends"] as? String
println(usernames) // It prints nil
if usernames != nil {
self.userArray.addObject(usernames!)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.friendListTableView.reloadData()
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return userArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Update - replace as with as!
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = userArray[indexPath.row] as? String
return cell
}
I've saved current user's friend list with PFRelation in class "User" in column "Friends", here's how I save it
class addUserViewController: UIViewController {
#IBOutlet weak var usernameTextField: UITextField!
#IBAction func addUser(sender: AnyObject) {
var query = PFUser.query()
query.whereKey("username", equalTo: usernameTextField.text)
println("Pass")
query.getFirstObjectInBackgroundWithBlock{ (object:PFObject!, error: NSError!) -> Void in
if error == nil {
let currentUser = PFUser.currentUser()
let friendList = currentUser.relationForKey("Friends")
var addFriend = object
if addFriend != nil {
friendList.addObject(addFriend)
println("added")
}
PFUser.currentUser().saveInBackgroundWithBlock{
(succeeded: Bool!, error: NSError!) in
if error != nil {
println("Error")
}
else {
println("saved")
}
}
}
}
}
and now I want to retrieve current user's friend list to show it in tableview but The problem is I can't update tableview to show current user's friend list, It's empty and there's no user list in tableview at all. Is my code correct for this method? If not please help me correct this code
here's the screenshot of my User's class table in parse
here's the screenshot of my current user's friend in parse which is save with PFRelation
Any help is appreciated, Thank you!
I haven't used Parse in a while, but if I'm not mistaken, the first query (in the first chunk of code) isn't built correctly. Should be like this:
var query:PFQuery = PFQuery(className: "User")
if let username = PFUser.currentUser().username {
query.whereKey("username", equalTo: username)
query.findObjectsInBackgroundWithBlock {....}
}
The difference here is that you query the current user's username and not the object itself. Does this help?
Change the array to NSMutableArray , and check if it appends the data.
var userArray: NSMutableArray = []
In retrieveMessages when trying to query the Parse "User" table use
var query = PFUser.query()
and then you are not passing the username as String
try
query.whereKey("username", equalTo: PFUser.currentUser().username)

Swift Converting PFQuery to String Array for TableView

I am trying to query all of the Parse users in my database and then display each individual user in their own cell in a tableview. I have set up my tableview, but I'm stuck on saving the user query to a string array that can be used within the tableview. I have created a loadParseData function that finds the objects in the background and then appends the objects queried to a string array. Unfortunately I am given an error message on the line where I append the data.
Implicit user of 'self' in closure; use 'self.' to make capture semantics explicit' This seems to me that it is suggestion that I use self. instead of usersArray. because this is within a closure, but I'm given another error if I run it that way, *classname* does not have a member named 'append'
Here is my code:
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray = [String]()
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadParseData(){
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error != nil{
println("\(objects.count) users are listed")
for object in objects {
userArray.append(object.userArray as String)
}
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return usersArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as SearchUsersRegistrationTableViewCell
let row = indexPath.row
//cell.userImage.image = UIImage(named: usersArray[row])
//cell.usernameLabel?.text = usersArray[row]
return cell
}
}
The problem is that userArray is an NSArray. NSArray is immutable, meaning it can't be changed. Therefore it doesn't have an append function. What you want is an NSMutableArray, which can be changed and has an addObject function.
var userArray:NSMutableArray = []
func loadParseData(){
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
self.userArray.addObject(object)
}
}
self.tableView.reloadData()
} else {
println("There was an error")
}
}
}
Also, because objects are returned as 'AnyObject' you will have to cast them as PFUsers at some point in order to use them as such. Just something to keep in mind
For getting the user's username and displaying it
// Put this in cellForRowAtIndexPath
var user = userArray[indexPath.row] as! PFUser
var username = user.username as! String
cell.usernameLabel.text = username

Resources