High Sierra update causes NSTableView to flip and scramble

950 views Asked by At

I'm updating an existing project which has worked fine for years to High Sierra. The view loads correctly and looks as it always has:

Normal(correct) appearance

Then, after I open a popup and close it again, the view moves things around, flips things, and generally looks very crazy:

Scrambled(wrong) appearance

Notice the Info title drops to the bottom, the left side text items reverse order, and the date and dropdown text flip. Mouse interaction seems very scrambled as well when this happens.

I'm not sure where to even start with solving this one, anyone have any ideas?

This is using xcode 9 beta 5 and High Sierra Beta 6.
Update: This is also in xcode 9 GM and High Sierra GM Seed

Update

I have determined this happens when I call reloadData on the NSTableView that this view is within. So the question now seems to be how to refresh the table data without it going wonky.

8

There are 8 answers

3
Sashah On BEST ANSWER

It seems that reloadData and also reloadDataForRowIndexes:columnIndexes: both produce odd behavior in High Sierra. My way around this is as follows:

-(void)refreshAllCells {
    NSMutableIndexSet* rowIndexes = [[NSMutableIndexSet alloc] init];
    if (self.myTable.numberOfRows != 0)
        [rowIndexes addIndexesInRange:NSMakeRange(0, (self.myTable.numberOfRows))];
    [self.myTable removeRowsAtIndexes:rowIndexes withAnimation:NO];
    [self.myTable insertRowsAtIndexes:rowIndexes withAnimation:NO];
}

If there is a better answer I would still love to see it.

0
Jeff Brown On

I experienced this as well. Further testing revealed that the contents were being drawn WHILE the tableview Data source was being updated. By eliminating a spurious update, I was able to eliminate the issue.

I reload the data in the draw method, however I have moved the data update code outside of that method. Not sure if this helps the OP, but it worked for me.

3
rootOfSound On

In IB, tick the checkbox to use CALayers on your tableView's views. I toggled them on for all the view's in the tableView view hierarchy and all the flipping stopped!

Can't post an image as I don't have enough reputation but this link shows the IB checkbox:

Interface Builder options

1
Ed Goes On

All of a sudden I received several mails from customers who complained about all table texts being shown vertically flipped. All of them use macOS Mojave.

After a lot of hacking, and trying the solutions detailed above (to no avail alas), I decided to disable the autoSave property of the NSTableView:

//Swift.print("Now setting autosaveName of primaryView to \(self.className).primary")
//primaryTableView.autosaveName = "\(self.className).primary"
//primaryTableView.autosaveTableColumns = true

Then the problem was instantly gone. But now my customers weren't able anymore to change and save the column widths and order. So, instead of doing it programatically with tableView.autosaveName = "autosavename"; I now set up the autoSave property in the Table view properties, and also checked 'Column information' in the Attributes Inspector (while showing xib file). And then it works just fine..

I use the currently latest version of Xcode (10.1 10B61), and the problems only surfaced when using macOS Mojava 10.14.0 - 10.14.2 . High Sierra and Sierra gave no trouble. Whether I compiled the project in High Sierra or Mojave made no difference.

So, I hope this helps for other people confronted with this bizarre problem. I think it's a bug in macOS Mojave.

0
Ruzard On

Had the same problem, reproducible on High Sierra and Mojave. The issue was with NSOutlineView autosaveName, other solutions didn't help. However I needed this feature.

Moving adding/reloading data to "viewDidAppear()" instead of "viewDidLoad()" solved the problem.

Edited: It happens only when:

  1. autosave is present
  2. items get loaded on viewDidLoad before sorting is applied
  3. the same list of items gets re-loaded after sorting is applied
  4. all of the above happens on viewDidLoad

If you try to access tableView.sortingDescriptors (or NSOutlineView) - it automatically applies sorting. If it happens before loading the data - it works ok.

Loading data on viewDidAppear still looks like a better option.

0
Paolo Musolino On

For me, adding wantsUpdateLayer in my subclass fixed the problem.

override open var wantsUpdateLayer: Bool { return true }

0
adam.wulf On

I'm seeing this as well in 10.13, when 10.12 had worked just fine. I was able to work around this problem by, oddly enough, re-adding the cell view's subviews in its [layout]:

- (void)layout{
    if([self needsLayout]){
        for(NSView* v in [[self subviews] copy]){
            [self addSubview:v];
        }
    }

    [super layout];
}
0
DarkDust On

I've encountered this bug as well and while implementing another answer I found the real reason for the bug due to an exception that now got raised:

In my case, reloadData was called again while reloadData was still being executed. This caused the rendering issues.

The "loop" was happening as a side-effect of calling tableView.makeView(withIdentifier: identifier, owner: self) in tableView(_:, viewFor:, row:). The owner: self caused awakeFromNib() of the controller getting called again which in turn triggered the reloadData(). In my setup, I was not (yet) using separate XIBs for the table cells but was using the cells that were setup inside the table view as visible Interface Builder.

So the solution was to change tableView.makeView(withIdentifier: identifier, owner: self) to tableView.makeView(withIdentifier: identifier, owner: nil) and also use separate XIBs for the table cells.