1

Update: I think there's a relationship between this window's level and this problem: This never happened when this window.level was set to .normal, but when it was set to background wallpaper level.

I met a bizarre phenomenon in NSTableView behavior when I tried calling reloadData() on it. After calling reloadData(), my NSTableView correctly displayed new table cells according to the data source, but what was weird is old cells weren't completely "removed" but they kind of left their "ghost trail" or "mark" in the table view.

See the image below:

You can see the old cells' marks, right?

I have exhausted all methods I could think of, including prepareForReuse, I even went to the extreme thing of removing all cells from superview (NSTableView) before reloading data, and set cell.identifier = "" to force table view to create a brand new cell every reload, but that didn't work either.

My code is very simple as below

Controller code:

// TodoListTableViewController.swift
eventStore.fetchReminders(matching: predicateIncompleteReminders) { reminders in
    self.reminders = reminders

    DispatchQueue.main.async { [self] in
        todoListTableView.reloadData()
    }
}

// still in TodoListTableViewController.swift
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    let reminder = reminders[row]
    let itemCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: CellViewIdentifierSet.TodoItemCellView.rawValue), owner: self) as! TodoItemCellView

    itemCell.todoItemTextField.stringValue = reminder.title
    itemCell.todoColorTextField.textColor = reminder.calendar.color

    if let date = reminder.dueDateComponents?.date {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm"
        itemCell.todoStartTimeTextField.stringValue = dateFormatter.string(from: date)
    } else {
        itemCell.todoStartTimeTextField.stringValue = ""
    }

    return itemCell
}

TodoItemCellView code:

import Cocoa

class TodoItemCellView: NSTableCellView {
    @IBOutlet var todoColorTextField: NSTextField!
    @IBOutlet var todoItemTextField: NSTextField!
    @IBOutlet var todoStartTimeTextField: NSTextField!

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        // Drawing code here.
        todoItemTextField.maximumNumberOfLines = 2
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        todoItemTextField.stringValue = ""
        todoStartTimeTextField.stringValue = ""
    }
}

I'm pretty confident that logically nothing can be wrong. I also double checked that only one table view in my storyboard and no double stacked views.

enter image description here

I'm running the app on my MacBook Pro (mid 2015).

Edit: I did a view hierarchy debugging session. The view hierarchy was like this:

However, what my app displayed looked like this (notice the blurred trail)

Is it safe to assume that my MacBook Pro 2015 has a poor-quality display that can't properly refresh the content? And won't this behavior show up on other people's computers?

Merkurial
  • 242
  • 3
  • 17
  • Can you show the code? – Ron Mar 23 '21 at 13:27
  • I would suspect that you might have two table views. It’s the kind of bug where I think “what would I do if I wanted to achieve this effect”, and two table views would be the obvious solution. – gnasher729 Mar 23 '21 at 13:50
  • Hi @Ron, I supplied my code and screenshot in the description please check! – Merkurial Mar 23 '21 at 14:45
  • Hi @gnasher729, unfortunately I have one and only one table view. FYI, this kind of bizarre behavior also occurred with NSCollectionView too :( – Merkurial Mar 23 '21 at 14:45
  • Have you Captured the View Hierarchy? Any special layers or backgrounds? What happens if you don't do `todoItemTextField.maximumNumberOfLines = 2` in `draw`? – Willeke Mar 23 '21 at 15:04
  • Hi @Willeke, I updated my question. No special layers or backgrounds whatsoever in debugged view hierarchy, however the trail still remained in the app. – Merkurial Mar 24 '21 at 13:37
  • Have you tried without setting `maximumNumberOfLines` in `draw`? `draw` should draw, nothing else. – Willeke Mar 25 '21 at 14:25
  • I just tried that too but unfortunately that didn't solve the problem either... :( – Merkurial Mar 25 '21 at 14:34
  • Sorry, I haven't had much time lately. Does this help? https://stackoverflow.com/a/54754584/11042467 – Ron Mar 25 '21 at 18:37
  • Have you tried `todoListTableView.needsDisplay = true` before or after `reloadData()`? – Willeke Mar 26 '21 at 08:53
  • Hi @Willeke I tried your suggestion but unfortunately that didn't work out for me :( – Merkurial Mar 29 '21 at 14:12
  • Hi @Ron, I saw the link you suggested but couldn't understand what I should do... If you wouldn't mind could you tell me some keywords that I should pay attention to in the above link? – Merkurial Mar 29 '21 at 14:16
  • @Merkurial What's in your makeView method, where you are passing owner as self? – Shivani Bajaj Apr 01 '21 at 07:59
  • Hi @ShivaniBajaj, I only use default TableView's `makeView` method, so I don't have any custom implementations in there. – Merkurial Apr 01 '21 at 08:30
  • (Aside: once you have done some research, it is fine to ask a Stack Overflow question. It is best to ask it confidently, and to omit any pleading, begging, desperation, frustration, annoyances, irritations, and so forth - any of the above are downvote magnets. Well-researched questions are welcomed, not tolerated. Stick to technical writing if you can). – halfer Apr 05 '21 at 15:46
  • I think there's a relationship between this window's level and this problem: This never happened when this window.level was set to `.normal`, but when it was set to background wallpaper level. – Merkurial Aug 08 '21 at 14:36
  • Check in the interface designer if any Core Animation Layers (last tab in the inspector panel) are enabled in any of the views in the tableview views hierarchy. Disable them and check what happens. – Ely Aug 08 '21 at 15:06
  • @Ely unfortunately there was no item that had Core Animation Layers checked in the beginning, I just verified that again :( I'm creating table cells programmatically though, do I have to disable CALayer in code? – Merkurial Aug 08 '21 at 15:39
  • @Merkurial No, I don't think so. The properties of the NSWindow instance could also play a role, like the deferred memory setting, animation, appearance (try for example Aqua instead of inherited), shadow, textured, etc. Experiment and see what happens. – Ely Aug 08 '21 at 17:10

0 Answers0