0

When I switch to another app, the next interaction I have with the view sometimes results in the error:

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

I have overridden the deinit method on the CustomViewController to log a message when it is called. The following messages are logged in the console when the above error occurs.

CustomViewController is being deallocated
*** -[AppName.CustomViewController release]: message sent to deallocated instance 0x604000121b80

It doesn't happen every time I switch back and forth between the app, but does seem consistent with a background garbage collection process cleaning up instances it thinks are not required any more.

My Cocoa App is relatively basic so far, all contained within the default Main.storboard generated when I first created project and then updated. No custom storyboard or controller initialisation code. Everything just loads up and displays when I run the app before hitting my own code.

I don't have any code to post that I think may be related to the problem.

There are no references in my code to the storyboard or the controllers that are instantiated when it is loaded. I haven't been able to find any detail on what is happening under the covers, to better understand what may be causing the problem.

There isn't anything standing out as a potentially problematic area that I should highlight.

The closest equivalent problem I was able to find on the web is this one. But in that scenario they are initialising their controller manually from the storyboard and were not managing the references to the instances created. The solution does suggest that some garbage collection is done when the app is moved to the foreground, which is consistent with what I'm seeing, but doesn't help me resolve the issue.

Another one is showing a similar error, but with the retain method failing rather than release. Again, this one involves programatically loading the nib (on iOS 5 in this case).

The error seems to only come up when I switch the app back to the foreground and it appears to be an attempt to release the view controller that has already been released. When I set a breakpoint in the deinit method, I can see that it is called on the instance fine before the release call fails because that same instance is already deallocated.

Given the simple setup involved, I'm sure I'm making some incorrect assumptions here. Any help would be very much appreciated.

Using Swift 4 on macOS 10.13.6 with Xcode 10.1

Tee
  • 21
  • 4

1 Answers1

1

Following the advice in this answer, I traced the problem to a custom NSTableHeaderCell, which had a reference to the CustomViewController. The deallocation error was always associated with an attempt to deallocate the custom NSTableHeaderCell.

I found two things that appear to be related:

  1. First, a bug in my code. Each time I updated data that impacted the columns of the NSTableView, I was re-creating and assigning a new custom NSTableHeaderCell instance even if one had already been assigned, so there were a lot of these instances hanging around waiting to be garbage collected.
  2. After fixing the issue above, the problem initially seemed to have been resolved, but eventually came up again after a longer period of time. Looking at the timing of the retain/release calls in the Instruments Zombies profiling template, it appears that there may have been a concurrency issue where multiple release calls were made as multiple NSTableViewCells were deallocated, which dropped the overall retain count of the CustomViewController to zero and then a subsequent retain call from somewhere on the remaining zombie reference that I assume should have come before the last release call.

I'm not 100% sure whether it was a concurrency issue or not, but changing the reference to the CustomViewController within the custom NSTableViewCell to a weak reference appears to have resolved the issue.

Still seems like there could still be a problem in my code that I haven't tracked down and using weak references is just working around it, but for the time being I'm assuming this is resolved.

Tee
  • 21
  • 4