Custom cells repeating - ios

I have an app that has a tableview embedded in a ViewController and whenever I navigate to another ViewController and navigate back to the table view, the cells repeat when I scroll. Does anyone have any advice on how to prevent this? The current code for the tableview is :
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return marathonRaces.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let singleCell: marathonTableViewCell = tableView.dequeueReusableCellWithIdentifier("marathonCell") as! marathonTableViewCell
singleCell.marathonName.text = marathonRaces[indexPath.row]
singleCell.entry.text = "\(entryNumber[indexPath.row])"
singleCell.entries.text = "\(entires[indexPath.row])"
singleCell.length.text = "\(length[indexPath.row])"
return singleCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = self.marathonsTableView.indexPathForSelectedRow!
let currentCell = marathonsTableView.cellForRowAtIndexPath(indexPath) as! marathonTableViewCell
let marathonEvents = currentCell.marathonName.text
self.performSegueWithIdentifier("marathonDetail", sender: self)
}
I am using swift, xcode7, and parse as my backend
the only relevant code within viewDidAppear would be :
var query = PFQuery(className: “Marathons")
query.orderByAscending("end")
query.findObjectsInBackgroundWithBlock { (marathons, error:NSError?) -> Void in
if(error == nil ){
//success
for marathon in marathons! {
self.marathonRaces
.append(marathon[“marathonName"] as! String)
self.entry.append(marathon[“entryNumber"] as! Int)
self.entries.append(marathon[“entries"] as! Int)
self.length.append(marathon[“length"] as! Int)
}
self.marathonsTableView.reloadData()
}else {
print(error)
}
}

The problem is in your viewDidAppear method. Every time the controller appears you fetch data from background, append them to your arrays and reload the tableview. Move the code for fetching data to viewDidLoad for example and "repeating" should be gone.

Have you checked to see if the datasource marathonRaces is gaining more entries?
You may be adding more entries on each back navigation, if so either do not add them or remove all entries prior to adding them.

Related

UITableViewCells won't load index is out of range

I am trying to load some data from CloudKit to populate a tableview with custom cells and I am having difficulty getting the data to appear.
When I define the number of rows as the count of the CKRecord array the tableview shows up, but with nothing loaded into them. They are just spaced out correctly for the images to be in there. Also, when I set breakpoints at let record = matches[indexPath.row] it won't trigger.
However, if I change the return matches.count to an actual number, the project crashes at let record = matches[indexPath.row]
with the error that the index is out of range. I want to keep the number of rows as the count for the record array, but that is the only change that will actually execute the override function that calls the tableview cell.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return matches.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Card", for: indexPath) as! MatchTableViewCell
let record = matches[indexPath.row]
if let img = record.value(forKey: "Picture") as? CKAsset {
cell.profileimg.image = UIImage(contentsOfFile: img.fileURL.path)
}
return cell
}
Any advice is appreciated
Update- here is where I load the model
func loadModel() {
let totalMatch = (defaults.object(forKey: "passedmatch") as! [String] )
let predicateMatch = NSPredicate(format: "not (UserID IN %#)", totalMatch )
ProfilesbyLocation = defaults.object(forKey: "Location") as! String
let query = CKQuery(recordType: ProfilesbyLocation , predicate: predicateMatch )
publicData.perform(query, inZoneWith: nil,completionHandler: ({results, error in
print("loading")
if (error != nil) {
let nsError = error! as NSError
print(nsError.localizedDescription)
print ("error")
} else {
if results!.count > 0 {
DispatchQueue.main.async() {
self.tableView.reloadData()
self.refresh.endRefreshing()
print("refreshed")
}
}
}
}
)
)}
It sounds like you are not calling
tableview.reloadData()
after your asynchronous data comes in. Leave numberOfRowsInSection as it is and make sure when your network request comes back you are reloading. That should do it.
If you received your data from background thread(or queue), please make sure when you update your UI elements under the main thread(or queue). Try this:
DispatchQueue.main.async {
tableView.reloadData()
}
This solved my problem.
First, disconnect the Delegate/DataSource of the TableView from the Interface Builder refer this image. When you have finally prepared your data that is matches array then add this.
`DispatchQueue.main.async {
tableView.dataSource = self
tableView.delegate = self
tableView.reloadData
}`
Hope this helps.
It looks like your matches is incorrect. Before you call func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)
, you should check your matches.
If you are still not sure about that. You can init your matches with string literals and have a try.

Setting one parse object of type array to a tableView

I know that I can query for, lets say, users that have emailVerified equal to true and present them into a tableView, but I was having trouble getting a single Parse object of type array into a tableView. I couldn't find anything online about this specific problem, but after putting a few answers together, I got it to work my answer is below for those also having trouble with this.
Here is what I found based on my question. I have an object in Parse called "my_classes" that is of type array. I want to get the items from the array into a tableView.
1) Create a variable: var myClassesResults : NSMutableArray = []
2) Create the function or place the code where necessary:
func getUserData() {
if PFUser.currentUser()!.objectForKey("my_classes") != nil {
let classes = PFUser.currentUser()!.objectForKey("my_classes")!
myClassesResults = classes as! NSMutableArray
self.noClasses = false
self.tableView.reloadData()
} else {
self.noClasses = true
self.tableView.reloadData()
}
}
3) tableView functions:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.myClassesResults.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = myClassesResults[indexPath.row] as? String
return cell
}

Repeating values on a table view cells Error from API response

I have a view (lets call it View 1) with a button on it. When the button is clicked I make a GET http request to my API. It sends back an array of objects.
Currently what I am trying to do is that when a user presses the button on view 1 the response data is passed to view 2 which is a tableView. And then fill up the table view cells with the returned data.
I am passing the returned JSON response from view 1 to view 2 like this:
dispatch_async(dispatch_get_main_queue()) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("BioView") as! BioTableViewController
vc.bioArray = parseJSON
self.presentViewController(vc, animated: true, completion: nil)
}
Where parseJSON contains the returned JSON response.
In View 2 I have the following:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.bioArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("bioCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
if bioArray.count > 0 {
let weatherSummary: AnyObject = bioArray[indexPath.row]
for x in bioArray {
if let id = x["employeeName"] as? String{
cell.textLabel?.text = id
}
}
}
return cell
}
The Issue:
The table view keeps repeating the last value in the returned JSON data. see below:
My Question:
How can stop the value from repeating and show all the values from the response data and when I click on the a tableview cell it goes to another view and shows all the details related to the clicked on cell.
You don't need to use for loop(because of it, table view keeps repeating value I guess). cellForRowAtIndexPath will do the same for you. Just try the code below :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("bioCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
let weatherSummary: AnyObject = bioArray[indexPath.row]
if let id = weatherSummary["employeeName"] as? String //Dont know the exact syntax.
{
cell.textLabel?.text = id
}
return cell
}
And to get rid of if bioArray.count > 0 condition you can do like
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.bioArray.count ?? 0 //This will return 0 rows if bioArray is empty.
}
Hope this will help!

tableView not loading data from parse

I have a function called loadData
func loadData(){
feedData.removeAllObjects()
var findFeedData:PFQuery = PFQuery(className: "userQuotes")
findFeedData.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?, error:NSError?)->Void in
if error == nil{
if let objs = objects{
for object in objs{
let quote:PFObject = object as! PFObject
self.feedData.addObject(quote)
}
let array:NSArray = self.feedData.reverseObjectEnumerator().allObjects
self.feedData = NSMutableArray(array: array)
self.tableView.reloadData()
}
}
}
}
and then in the cellForRowAtIndexPath I actually get the data and display it. I self.loadData() in the viewDidLoad function.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:QuoteTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! QuoteTableViewCell
let quote:PFObject = self.feedData.objectAtIndex(indexPath.row) as! PFObject
cell.contentTextView.text = quote.objectForKey("content") as! String
// Configure the cell...
return cell
}
I am getting no compiler errors and everything seems to be working. The content gets pushed to parse but it doesn't load with these functions. All that runs is an empty table view cells When it should be displaying content from Parse. I feel I am missing something simple logically here... I am a beginner so pardon any silly mistakes. I am following a tutorial but that is a bit outdated.
If you are using a mutable array, you will need to initialize it before adding in objects.
You are changing UI on an asynchronous thread.
The call to parse is async. When this call completes you are reloading your table view.
You should instead dequeu your UI change to the main thread
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
Verify these methods:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1 //or more if you want
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feedData.count
}

UITableView cell duplicates

I'm working on my first Swift app, and stuck on a bug forever. When adding a new entry to the coredata, everything goes fine the first time. However, with additional items, the previously added item is duplicated in the table.
The data is not duplicated, only the cell. When the app is reloaded, the cells are displayed correctly.
Here's the code that populates the cells:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if let fetchedSections: AnyObject = fetchedResultController.sections as AnyObject? {
return fetchedSections.count
} else {
return 0
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let fetchedSections: AnyObject = fetchedResultController.sections as AnyObject? {
return fetchedSections[section].numberOfObjects
} else {
return 0
}
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let lookup = sortedArray[indexPath.row] as! NSManagedObjectID
let spot = spotsDict[lookup] as! Spots
let cell = tableView.dequeueReusableCellWithIdentifier("SpotCell", forIndexPath:indexPath) as! SpotCell
println(sortedArray)
println(spot)
cell.spotLabel.text = spot.title
cell.spotPhoto.image = self.imagesDict[lookup]
cell.distanceLabel.text = self.distanceStringDict[lookup] as NSString! as String
cell.spotPhoto.layer.cornerRadius = 4
cell.spotPhoto.clipsToBounds = true
return cell
}
Please replace your code
let lookup = sortedArray[indexPath.row] as! NSManagedObjectID
with below code in cellForRowAtIndexPath method.
let lookup = sortedArray[indexPath.section] as! NSManagedObjectID
The root of the problem was in my sorting method.. simplified the code a lot, and sorted with sortDescriptors instead.

Resources