Unable to eliminate last talbeviewcell (when search is empty) - ios

I use this code to search for all files that are off in "review",
And there is a button to change "review" to "on". When "review" is changed to "on"(because the code only searches for "off"), the tableviewcell will disappear normally.
But every time the last stroke will not disappear(tableview can't find the file), you need to restart the app to clear the tableviewcell,
Why is this?
let db = Firestore.firestore()
db.collectionGroup("TWDBuy").whereField("review", isEqualTo: "off")
.order(by: "date", descending: true)
.addSnapshotListener { (snapshot, error) in
This is tableview
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TWDBuyPGTableViewCell") as! TWDBuyPGTableViewCell
let post = self.postArray[indexPath.row]
let date = post.date
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.timeZone = TimeZone(identifier:"Asia/Taipei")
dateFormatter.locale = Locale.init(identifier: "zh_Hant_TW")
dateFormatter.setLocalizedDateFormatFromTemplate("yyyy-MM-dd HH:mm")
let dateStr = dateFormatter.string(from: date)
if postArray[indexPath.row].review2 == "未確認"{
cell.review2.textColor = UIColor(red: 255.0/255.0, green: 192.0/255.0, blue: 0.0/255.0, alpha: 1)
}else{
cell.review2.textColor = UIColor(red: 55.0/255.0, green: 163.0/255.0, blue: 152.0/255.0, alpha: 1)
}
cell.quantity.text = "數量:"+postArray[indexPath.row].quantity+" USDT"
cell.coin.text = "匯入: TWD "+postArray[indexPath.row].coin
cell.address.text = postArray[indexPath.row].address
cell.network.text = postArray[indexPath.row].network
cell.email.text = postArray[indexPath.row].email
cell.review2.text = postArray[indexPath.row].review2
cell.uid.text = postArray[indexPath.row].uid
cell.useruid = post.uid
cell.useremail = post.email
cell.commentDelegate2 = self
cell.time.text = dateStr
cell.idimage.sd_setImage(with: URL(string: postArray[indexPath.row].ID5))
cell.deleteThisCell2 = { [weak self] in
self!.delete2(didSelectRowAt: indexPath, cell: cell)
}
cell.deleteThisCell3 = { [weak self] in
self!.delete3(didSelectRowAt: indexPath, cell: cell)
}
let settings = Settings.defaultSettings
.with(actionOnTapOverlay: Action.dismissOverlay)
.with(actionOnDoubleTapImageView: Action.zoomIn)
addZoombehavior(for: cell.idimage, settings: settings)
getUserPortfolio(didSelectRowAt: indexPath)
//刷新
self.usertableview.es.addPullToRefresh {
[unowned self] in
/// Do anything you want...
/// ...
/// Stop refresh when your job finished, it will reset refresh footer if completion is true
self.usertableview.es.stopPullToRefresh()
/// Set ignore footer or not
self.usertableview.es.stopPullToRefresh()
}
return cell
}
I have updated the tableview, and there is nothing in the snapshot. If the tableviewcell has a "review" off, modifying each "review" to on will reduce it normally, but the last one will not disappear (firebase "review" is all on)

Related

How to trigger refresh in Supplementary view of UICollectionView

We are using UICollectionView to draw a calendar. The supplementary view is used for the date at the top of a column that represents a day in the calendar. Each calendar is a section in the UICollectionView. We want the current day highlighted. We have that working by
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var view: UICollectionReusableView?
if kind == WeeklyCollectionElementKindDayColumnHeader {
let dayColumnHeader: WeeklyDayColumnHeader? = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: WeeklyDayColumnHeaderReuseIdentifier, for: indexPath) as? WeeklyDayColumnHeader
let day: Date? = collectionViewCalendarLayout?.dateForDayColumnHeader(at: indexPath)
let currentDay: Date? = currentTimeComponents(for: self.collectionView!, layout: collectionViewCalendarLayout!)
let startOfDay: Date? = Calendar.current.startOfDay(for: day!)
let startOfCurrentDay: Date? = Calendar.current.startOfDay(for: currentDay!)
dayColumnHeader?.day = day
dayColumnHeader?.isCurrentDay = startOfDay == startOfCurrentDay
view = dayColumnHeader
}
else if kind == WeeklyCollectionElementKindTimeRowHeader {
let timeRowHeader: WeeklyTimeRowHeader? = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: WeeklyTimeRowHeaderReuseIdentifier, for: indexPath) as? WeeklyTimeRowHeader
timeRowHeader?.time = collectionViewCalendarLayout?.dateForTimeRowHeader(at: indexPath)
view = timeRowHeader
}
return view!
}
which with this
class WeeklyDayColumnHeader: UICollectionReusableView {
var day: Date? {
didSet {
var dateFormatter: DateFormatter?
if dateFormatter == nil {
dateFormatter = DateFormatter()
dateFormatter?.dateFormat = "E d"
}
self.title!.text = dateFormatter?.string(from: day!)
setNeedsLayout()
}
}
var isCurrentDay: Bool = false {
didSet {
if isCurrentDay {
title?.textColor = UIColor.white
title?.font = UIFont.boldSystemFont(ofSize: CGFloat(16.0))
titleBackground?.backgroundColor = UIColor(red:0.99, green:0.22, blue:0.21, alpha:1.0)
}
else {
title?.font = UIFont.systemFont(ofSize: CGFloat(16.0))
title?.textColor = UIColor.black
titleBackground?.backgroundColor = UIColor.clear
}
}
}
set the background we want the first time I come into this view. But if I have this view open and the date changes, how do I update the header? Where should I move the logic that sets the date, and how do I "invalidate" or whatever I need to do?
Use the UIApplicationSignificantTimeChangeNotification in order to notify you of time changes.
Use the NotificationCenter to implement this. Something like this:
NotificationCenter.defaultCenter().addObserver(self, selector: "dayChanged:", name: UIApplicationSignificantTimeChangeNotification, object: nil)
Then you need a function to handle the change:
func dayChanged(notification: NSNotification){
// trigger the changes you need here
}

Reloading table view without user interactions while app is foreground

Swift provides a powerful way to update table view changes when you're using reloadData(). But it's works on the certain places as such viewDidLoad and viewDidAppear or refreshControl. It would be better when the tableView gets an automatic way to reload data. It's possible to update the tableView when the app is foreground? You can see such as effect in the iOS Reminders app.
Example: iOS Reminder
Let's say you've scheduled reminder. And you're still using the app, at this time your scheduled notification is fired and prompted about you must be do something. At this time your scheduled reminder becomes an overdue item, when you're doing nothing and the detailTextLabel gets a red color. There is no any user interactions.
Here's what I've done:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let managedObject = self.fetchedResultsController.object(at: indexPath)
cell.textLabel?.text = managedObject.value(forKey: "string") as? String
cell.detailTextLabel?.text = "\(managedObject.value(forKey: "date") as! Date)"
print("Get called")
for viewController in (self.tabBarController?.viewControllers)! {
let overdue = self.fetchedResultsController.fetchedObjects?.filter({ (record) -> Bool in
return (record.date?.compare(Date()) != .orderedDescending)
})
if viewController.tabBarItem.tag == 1 {
if overdue?.count == 0 {
DispatchQueue.main.async(execute: {
viewController.tabBarItem.badgeValue = ""
viewController.tabBarItem.badgeColor = UIColor.clear
})
} else if overdue?.count != 0 {
DispatchQueue.main.async(execute: {
viewController.tabBarItem.badgeValue = "\(overdue!.count)"
viewController.tabBarItem.badgeColor = UIColor.init(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0)
})
}
}
}
DispatchQueue.main.async {
if managedObject.date?.compare(Date()) != .orderedDescending {
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.black
}
}
return cell
}
Thanks

Stop expanding UITableView from reloading contents incorrectly - Swift 3

I have a UITableView that expands when a particular cell is tapped. My problem is that on first load or expand of the table the additional cells load the contents correctly but with successive closing and expanding of the table things load incorrectly.
My code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: currentCellDescriptor["cellIdentifier"] as! String, for: indexPath) as! CustomCell
if currentCellDescriptor["cellIdentifier"] as! String == "idCellTextfield" {
cell.photo.image = globalVariable.images2[(indexPath as NSIndexPath).row]
cell.name.text = globalVariable.names2[(indexPath as NSIndexPath).row]
cell.price.text = globalVariable.prices2[(indexPath as NSIndexPath).row]
cell.unitPrice.text = globalVariable.unitPrice2[(indexPath as NSIndexPath).row]
cell.pPrice.text = globalVariable.previousPrice2[(indexPath as NSIndexPath).row]
//This is the portion of code that loads incorrectly
//This code identifies if an item is on special (true or false) and if it is adds a border to the left of the cell, specifies saving amount and changes the colour and style of some labels.
if globalVariable.specialBool2[(indexPath as NSIndexPath).row] == true {
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: globalVariable.previousPrice2[(indexPath as NSIndexPath).row])
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
cell.pPrice.attributedText = attributeString;
cell.price.textColor = UIColor(red: 214/255, green: 14/255, blue: 0/255, alpha: 1.0)
cell.layer.addBorderWatchlist(UIRectEdge.left, color: UIColor(red: 214/255, green: 14/255, blue: 0/255, alpha: 1.0), thickness: 6)
cell.savingAmount.text = globalVariable.savingAmount2[(indexPath as NSIndexPath).row]
} else if globalVariable.specialBool2[(indexPath as NSIndexPath).row] == false {
cell.pPrice.text = " "
cell.savingAmount.text = " "
cell.savingLbl.isHidden = true
cell.savingAmount.isHidden = true
}
}
cell.delegate = self
return cell
}
What do I have to change in the relevant portion of code to ensure that the contents reloads correctly each time the table is expanded?

Image view inside custom table view cell disappears when cell inserted into table

This is my first time dealing with iOS development. I'm creating an app that uses a custom UITableViewCell to display information retrieved from Core Data. Im having this issue where an imageView that displays a color disappears randomly when the cell is inserted into the table. If the image view does disappear, closing the app and restarting it will fix the problem.
Right after inserting into table: pic
After force closing app and restarting: pic
Any advice on where the problem is would be appreciated.
Here is some of the relevant code. Im using NSFetchedResultsController too if that helps.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> CustomTableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomTableViewCell
let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
self.configureCell(cell, withObject: object)
return cell
}
func configureCell(cell: CustomTableViewCell, withObject object: NSManagedObject) {
let imageData: NSData = object.valueForKey("image") as! NSData
let colorImageBlank: UIImage = UIImage(named: "blank.png")!
let picture: UIImage = UIImage(data: imageData)!
let date: NSDate
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale.currentLocale()
cell.cellImage.image = picture
let colorString = object.valueForKey("color")!.description
var color: UIColor = UIColor()
if colorString == "Blue" {
color = UIColor.blueColor()
} else if colorString == "Red" {
color = UIColor.redColor()
} else if colorString == "Green" {
color = UIColor.greenColor()
} else if colorString == "Yellow" {
color = UIColor.yellowColor()
} else if colorString == "Orange" {
color = UIColor.orangeColor()
} else if colorString == "Purple" {
color = UIColor.purpleColor()
}
cell.colorImage.image = colorImageBlank
cell.colorImage.backgroundColor = color
cell.colorImage.layer.cornerRadius = 5.0
cell.cellImage.layer.borderWidth = 2
cell.cellImage.layer.borderColor = color.CGColor
cell.cellImage.layer.cornerRadius = 5.0
cell.locationNameLabel.text = object.valueForKey("name")!.description
cell.locationNameLabel.font = UIFont.boldSystemFontOfSize(14.0)
cell.locationNameLabel.lineBreakMode = NSLineBreakMode.ByTruncatingTail
cell.categoryLabel.text = object.valueForKey("category")!.description
cell.categoryLabel.font = UIFont.italicSystemFontOfSize(12.0)
cell.categoryLabel.lineBreakMode = NSLineBreakMode.ByTruncatingTail
date = object.valueForKey("date")! as! NSDate
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
cell.dateLabel.text = dateFormatter.stringFromDate(date)
cell.descriptionLabel.text = object.valueForKey("descript")!.description
cell.descriptionLabel.lineBreakMode = NSLineBreakMode.ByTruncatingTail
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Update:
self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)! as! CustomTableViewCell, withObject: anObject as! NSManagedObject)
case .Move:
tableView.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!)
}
}
It seems to be an issue of framing because not only image view two other labels for date and other label is also missing, Are you adding constraints to it?
From the code you've shared I can suggest the following:
check your configureCell method, seems like it's nil for that period of time.
I've made such conclusion from your first screenshot: instead of text, You have placeholder specified on Your storyboard/ xib.
So, check if
let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
returns the proper object from your fetch controller (update it, if that is not true).
Hope this helps.

UITableViewCell not removed from the UITableView when using reloaddata

I'm using a tableview to display some categories in a left menu. When you select it, the data in the cells changes to courses ('Cursussen') within that category.
Each cell contains an UIImageView and an UILabel.
I noticed a while ago that when you select a course in the left menu, the label will change to that of a category. That wasn't a big issue back then, but now that I'm working to disable certain courses if they are not available it suddenly became a big issue. To indicate a course that's not available, I'm setting label.enabled = false, which works fine, however I also need to prevent the user from tapping on it and navigating to a course that's not available. To do that, I'm using tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) where I check whether the UILabel is enabled. If it's disabled the App won't navigate to the course.
Back to the issue, tapping on a course that is unavailable (which is displaying the correct image and label) will trigger the didSelectRowAtIndexPath delegate, but when I dequeue the Cell and check whether the UILabel in it is disabled it so happens to be enabled instead and furthermore the label.text does not equal the value I see in the App.
State before selecting a row:
State after selecting a row:
cellForRowAtIndexPath method:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("LeftCell", forIndexPath: indexPath)
let label = cell.contentView.subviews[0] as! UILabel
let image = cell.contentView.subviews[1] as! UIImageView
if(selectedCategory.ID > 0 || searchCursusses.count > 0) {
//Category is selected, load course into cell
var cursus : Cursus
if(selectedCategory.ID > 0) {
cursus = cursusses[indexPath.row] as Cursus
} else {
cursus = searchCursusses[indexPath.row] as Cursus
}
image.image = self.chooseImage(false, name: cursus.category!.Name)
label.numberOfLines = 0
label.text = cursus.name
label.lineBreakMode = .ByTruncatingTail
if(defaults.boolForKey("offline-mode")) {
let realm = try! Realm()
let videos = realm.objects(DownloadedVideo).filter("video.cursus.ID = %#", cursus.ID)
if(videos.count > 0) {
label.enabled = true
} else {
label.enabled = false
}
} else {
label.textColor = UIColor.blackColor()
}
cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell.setSelected(false, animated: false)
} else {
let category = categories[indexPath.row] as Category
image.image = self.chooseImage(false, name: category.Name)
label.numberOfLines = 0
label.text = category.Name
label.lineBreakMode = .ByTruncatingTail
label.textColor = UIColor.blackColor()
cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
return cell
}
didSelectRowAtIndexPath method:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath)
cell.selectionStyle = .None
if(selectedCategory.ID > 0 || searchCursusses.count > 0) {
let label = cell.contentView.subviews[0] as! UILabel
if(!label.enabled) {
return
}
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewControllerWithIdentifier("CursusView") as! CursusViewController
if(selectedCategory.ID > 0) {
resultViewController.loadCursus(self.cursusses[indexPath.row], completionHandler: {
self.presentViewController(resultViewController, animated:true, completion:nil)
})
} else {
resultViewController.loadCursus(self.searchCursusses[indexPath.row], completionHandler: {
self.presentViewController(resultViewController, animated:true, completion:nil)
})
}
} else {
let category = categories[indexPath.row] as Category
cell.setSelected(true, animated: false)
let label = cell.contentView.subviews[0] as! UILabel
let image = cell.contentView.subviews[1] as! UIImageView
if(label.textColor == UIColor.lightGrayColor()) {
return
} else {
image.image = self.chooseImage(true, name: category.Name)
label.numberOfLines = 0
label.text = category.Name
label.textColor = UIColor.whiteColor()
label.lineBreakMode = .ByTruncatingTail
cell.backgroundColor = UIColor(red: 45.0/255.0, green: 145.0/255.0, blue: 220.0/255.0, alpha: 1.0)
self.selectedCategory = category
self.topBarTitle.text = category.Name
let realm = try! Realm()
let cursusses = realm.objects(Cursus).filter("category.ID = %#", selectedCategory.ID)
for cursus in cursusses {
self.cursusses.append(cursus)
}
let title = self.leftMenuNav.subviews[0] as! UILabel
let titleImg = self.leftMenuNav.subviews[1] as! UIImageView
titleImg.image = UIImage(named: "back-icon")
title.text = "Cursussen"
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.slideInFromRight(0.5)
self.tableView.reloadData()
self.collectionView.crossFade(0.3)
self.collectionView.reloadData()
})
}
}
}
It seems the old cells are not properly cleaned up after calling reloaddata, causing multiple cells to be at the same IndexPath.
I'm at a loss here, please help!
The problem is the line
let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath)
in the didSelectRowAtIndexPath function because it is creating a new cell (or trying to reuse one) and corrupting the table view cell cache.
You should be getting the existing cell instead using the cellForRowAtIndexPath function.
You have a problem with your approach: didSelectRowAtIndexPath is supposed to look at the data in the model, not in the view. Your code is trying, incorrectly, to access the cell and examine its labels etc. Instead, your method should be accessing the same underlying data source that has been used to make the labels in the first place.
In other words, instead of writing
let label = cell.contentView.subviews[0] as! UILabel
and then examining the enabled/disabled status of the label
you should write
cursus = cursusses[indexPath.row] as Cursus
and examine the availability of the cursus.
One general rule of thumb is that you should get very suspicious when you see code accessing components of UITableViewCell outside cellForRowAtIndexPath. Testing the state of a label is nearly universally an indication that the code is incorrect.
Man you are doing that wrong. Only tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell can dequeue cells and setup its contents.
To prevent selection you should react on func tableView(_ tableView: UITableView,
willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath and return nil to indicate that you don't want to select anything.
Main problem is that you are writing to complex methods. It is hard to figure out what are you doing and what is you intention. (will/did)SelectRowAtIndexPath should invoke only one/tow some simple methods, for example: perform a segue or load some data.

Resources