PFUser query taking time to fetch users from Parse - ios

Here is my viewDidLoad method -
var query = PFUser.query()
query.findObjectsInBackgroundWithBlock({ ( objects : [AnyObject]! , error: NSError! ) -> Void in
//self.users.removeAll(keepCapacity: true)
for object in objects {
var user:PFUser = object as PFUser
println(user.username)
self.users.append(user.username)
}
self.tableView.reloadData()
})
println( " Count \(users.count) ")
The count of users gets printed before the usernames in the users which makes me believe that it is taking time to fetch the users from the database. And for that reason my tableView never gets updated, the code for which looks like this -
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = users[indexPath.row]
return cell
Gives me an 'Array index out of range error' because the number of rows in my table is three while my dictionary is empty.
Couldn't find any particular solution on swift. Any suggestions?
EDIT : Forgot to mention that the users do get printed but after a long time (even after the count of the users which are being printed after the usernames are)
Just for the information, count is always printed as 1.
The output is something like this -
Count 1
genaks
genaks1427
genaks14271
adu
afd

I shifted my the code in my viewDidLoad function to the viewDidAppear function and it works just about the way I wanted it to work :)

If you can, do the findObjectsInBackgroundWithBlock query inside the cellForRowAtIndexPath method. Check this tutorial: https://www.youtube.com/watch?v=Q6qcrO8uNzU he does the same in video.

When you said "the number of rows in my table is three" you inferred that in numberOfRowsInSection you returned 3.
If I'm right, I believe that's the problem.
You have to do it like this
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
This way the numberOfRowsInSection will never be different from the intended amount.

Related

Want to return only 1 cell in uitablelview but due to json response multiple cells are getting displayed

I'm having an array of data that is being retrieved from a JSON. Storing that data into modal of struct. Also, I have a UITableView to display that data.The problem is that I'm getting multiple entity of response but want to show only one cell at a time. By returning 1 in numberOfRowsInSection is not working.
If I return 1 in numberOfRowsInSection then it gives an error
index out of bound exception
suppose you are storing your response in array named arrResponseData then you need to write your code like this to achieve your desired result.
You were getting index of bound issue because your tableview gets loaded before you store data in array and compiler do not get any index, so it fails with index out of bound
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(arrResponseData && arrResponseData.count>0) {
return 1
} else {
return 0
}
}

Filter an array of items by their date parameter without taking time into account

I have an array of Dates which I'd like to filter, depending on a date selected by a user. However, since each object has also time, I am having a hard time filtering correctly.
In my table view, I would like to filter this array of items by their date parameter without it comparing the time. Aka:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.filter({$0.date == selectedDate}).count
//count is always 0 because time is not exactly the same in any instance
}
Any ideas on how I can do this?
Try using this function of the system calendar
Calendar.current.isDate($0.date, inSameDayAs: selectedDate)
Here is the apple documentation for this function in case you have an additional clarifying questions
https://developer.apple.com/documentation/foundation/calendar/2292885-isdate

Populate Number of rows in section from CoreData when there are 2 sections

In my CoreData, I have a Person entity, and each Person can have multiple (to Many) Statement entities. The statement entity has an attribute called amountOwed which is a decimal amount. Right now my idea is to loop over all the amounts and add them up, if they of a positive amount add them to the positive array and if they are negative amount add them to that array. Then use that array to figure out how many cells each sections needs to display.
I created a fetchedResultsController and I am trying to use that for the for loop
for i in 0..<fetchedResultsController.fetchedObjects!.count {
let person = fetchedResultsController.fetchedObjects?[i]
let amountTotal = person?.value(forKeyPath: "statement.#sum.amountOwed") as? Decimal
if(amountTotal! <= Decimal(0) )
{
postiveCellNumber += 1
print("\(postiveCellNumber) postive number count")
}
else{
negativeCellNumber += 1
print("\(negativeCellNumber) negative number count")
}
}
Then, I'm trying to use those arrays in the numberOfRowsInSection function like so:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch(section) {
case 0:
return postiveCellNumber
case 1:
return negativeCellNumber
default :return 0
}
}
I don't think my for loop is looping properly as I get an error that says
no object at index 2 in section at index 0.
How about using two different queries, one for the positive values and one for the negative ones, with two different fetched results controllers? Then you can let the FRC do the iterating and counting for you.
You won't be able to use the FRCs to manage sections. You'll have to do that yourself. Specify nil for the sectionNameKeyPath. Then you want something like
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return positiveResultsController.fetchedObjects?.count ?? 0
}
else {
return negativeResultsController.fetchedObjects?.count ?? 0
}
}
or maybe
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
let sectionInfo = positiveResultsController.sections![section]
return sectionInfo.numberOfObjects
}
else {
let sectionInfo = negativeResultsController.sections![section]
return sectionInfo.numberOfObjects
}
}
with similar logic for tableView(_:cellForRowAt:).
It's very difficult to identify the specific cause of the error, without seeing more of how your FRC and tableView are constructed. But this bit looks suspicious:
if(amountTotal! <= Decimal(0) )
{
postiveCellNumber += 1
print("\(postiveCellNumber) postive number count")
}
Surely the if condition is back to front: you should increment the positiveCellNumber if amountTotal! >= Decimal(0)?
But that aside, even if you successfully calculate the counts, you will then face the issue of working out which of the FRC's fetchedObjects should appear in each row of each section:
You could do this "on the fly" in cellForRowAt, but that will involve iterating through the fetchedObjects again, to determine which appear in which section, which is clumsy and inefficient.
You could separate the fetchedObjects out into two separate arrays as a one-off step, once the FRC has done its performFetch. But you then need pretty ugly FRC delegate methods to update the two arrays whenever the FRC's fetchedObjects array is updated.
You could configure your FRC to automatically assign its fetched objects to the correct section, by specifying a sectionNameKeyPath and associated sort descriptors for the underlying fetch. The problem here is that it is not possible to sort the fetch using a calculated figure. If you want to pursue this route, you will need to add a totalAmountOwed attribute to your Person entity, and to ensure it is updated whenever the related Statements change.
Alternatively, you could follow #HalMueller's suggestion, and use two separate FRCs. You would use complementary predicates for the underlying fetches, one to get only those Persons with positive amount owed, the other to get those with negative amount owed. You can then use the fetchedObjects array for one FRC to populate section 0, and the other FRC to populate section 1. Overall, I think this is the solution I would recommend.

Parse.com query not working properly

I am trying to filter the posts based on their profile. For instance, when I go to my profile I only want to see my posts, not all the posts in my database. I attempted to make a filter for that but the code below does not seem to work and I am unsure as to why that is. It may be something obvious but I can not seem to pinpoint the issue, any ideas?
I have attached a picture of the database to further assist anybody.
The code runs perfectly fine it just does not filter the usernames.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var user = PFUser.currentUser()?.username!
let bucketCellObj = tableView.dequeueReusableCellWithIdentifier("bucket", forIndexPath: indexPath) as! BucketTableViewCell
var query = PFQuery(className: "Bucket")
query.whereKey("creator", equalTo: user!)
query.findObjectsInBackgroundWithBlock { (PFObject, error) -> Void in
if error == nil {
bucketCellObj.bucketname.numberOfLines = 0
bucketCellObj.username.text = self.bucketsArray[indexPath.row]["creator"] as? String
bucketCellObj.bucketname.text = self.bucketsArray[indexPath.row]["name"] as? String
bucketCellObj.selectionStyle = .None
} else {
print("ERROR")
}
}
return bucketCellObj
}
What you are doing here might work under some circumstances but will certainly bite you at some point.
What your code does:
show some arbitrary number of cells - probably based on self.bucketsArray.count or something similar
in each cell creation, run a parse query
when the query returns, customize the already displayed cell accordingly - without any usage of the requested query response
That will cause problems for a couple of reasons:
you perform too many requests, each cell requests some data, each new displayed cell requests its own data again
you display the old data in the cell until the new data is fetched which could take a few seconds due the amount of requests
you could encouter a problem where you requests some data for a cell, that cell moves off-screen, gets reused, then the first query returns, still holds the reference to it and will therefore display wrong data
How it can be solved
Do not requests the data in the cellForRowAtIndexPath.
Request the data once in viewDidLoad or similar. as soon as the data gets returned, parse it and initiate a tableView.reload().
In the cellForRowAtIndexPath make use of the already retrieved data, do not perform anymore async tasks.

Multiple Sections UITableViewController with PFObjects

I am building a very simple timetable iOS app to test out Swift and Parse.com as a backend.
I have an object type in my Parse database called "Class" (for school classes). These are simple objects that contain a name and dayOfWeek (Monday - Friday).
I want to display these similar to the iOS Calendar app 'list view', with a section of each day: Monday, Tuesday, Wednesday, Thursday and Friday (not actual dates like the Calendar app, just the week day name).
Then I want to display under each day, only the PFObjects returned from a query with same dayOfWeek as the relevant section.
I tried achieving this with a PFQueryTableViewController, but got weird issues with no section names and random empty cells throughout the table.
I believe that I need to take the following approach, but so help would be highly appreciated.
Retrieve a PFQuery of all my Class objects
Set numberOfSectionsInTable to 7 (one for each day)
Set titleForSection to appropriate names
In cellForRowAtIndexPath, cycle through returned Class objects, allocating each to the correct section based on dayOfWeek. Not sure how to do this part.
I have searched around and found that there seems to be no clear tutorials or documentation on how to show PFObjects from a PFQuery in multiple sections, sorted by one of the values of the object.
Any help would be appreciated. I believe this will help a lot of other people too.
You could create dynamic sections with a 2D array containing the name of the current section and an array to hold the the items.
You can then simply call
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return sectionItems.items[section].count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return sectionItems.items[section].count
}
sectionItems can be created using this class with takes a string and an array as a parameter
class SectionItems:NSObject{
var sections:[String] = []
var items:[[String]] = []
func addSection(section: String, item:[String]){
sections = sections + [section]
items = items + [item]
}
}
You can the call the function by using
self.sectionItems.addSection("Intro", item: self.intro)

Resources