Custom NSView crashes app but runs fine in Xcode

Hi,

I have created a reusable NSView (backed by a .xib file) that I add twice to a storyboard by adding CustomView object and changing the name of the class.

When I run the code from inside Xcode (on both intel and m1 macs) the code runs as expected.

When I create a binary (via Project Archive) the code crashes when it tries to load the Storyboard with the error:

Code Block
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<NSSlider 0x7fc5c740d8e0> has reached dealloc but still has a super view. Super views strongly reference their children, so this is being over-released, or has been over-released in the past.'

I have split the code out of the main project into a test project to see if the problem still occurred and it does. So it must have something to do with my implementation.

I understand what the error means, but as it works in Xcode I'm not sure how to go about trying to resolve this.

Can anyone provide some guidance as to how to fix this?

Thanks

Test project code is here : https://github.com/githublemming/BugCode

Accepted Reply

I am pretty sure it will work without a xib.

xib solution must work, but you need to manage topLevelObjects. Which is not totally immediate…

Replies

Did you try declaring the NSSlider as strong (remove weak) ?
Thanks for the suggestion. I just tried that and got the same error.
I get many errors in Xcode:

2021-03-14 13:39:24.562545+0100 BugCode[44764:3798589] CDN - client insert callback function client = 0 type = 17 function = 0x7fff322a4246 local_olny = false
2021-03-14 13:39:24.562599+0100 BugCode[44764:3798589] CDN - client setup_remote_port
2021-03-14 13:39:24.562627+0100 BugCode[44764:3798589] CDN - Bootstrap Port: 1799
2021-03-14 13:39:24.562771+0100 BugCode[44764:3798589] CDN - Remote Port: 23599 (com.apple.CoreDisplay.Notification)
2021-03-14 13:39:24.562812+0100 BugCode[44764:3798589] CDN - client setup_local_port
2021-03-14 13:39:24.562834+0100 BugCode[44764:3798589] CDN - Local Port: 23811
2021-03-14 13:39:24.578916+0100 BugCode[44764:3798626] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x60000024c1e0> F8BB1C28-BAE8-11D6-9C31-00039315CD46
2021-03-14 13:39:24.636908+0100 BugCode[44764:3798626]  HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine

You have defined KaraokeSongDragDestinationViewDelegate
But no-one conforms to it. Is it because you have just ket a bug-report part of code ?

Note: I was also missing the "icon_play" but replaced by another image.
I looked at doc for:
Code Block
func instantiate(withOwner owner: Any?, topLevelObjects: AutoreleasingUnsafeMutablePointer<NSArray?>?) -> Bool


Parameters
owner
The object to set as the Nib’s owner (File’s Owner).
topLevelObjects
On return, an array containing the top-level objects of the nib.
Return Value
true if the nib is instantiated; otherwise false.
Discussion
Unlike legacy methods, the objects adhere to standard Cocoa memory management rules; it is necessary to keep a strong reference to the objects or the array to prevent the nib contents from being deallocated. 
Outlets to top level objects should be strong references to demonstrate ownership and prevent deallocation.

But you pass nil for topLevelObjects.

Could you try changing to follow those requirements ?
Some info here: https://stackoverflow.com/questions/41312945/instantiate-nsview-with-custom-objects-in-it-using-nsnib

Other solution (I usually use):
I do not declare IBOutlets
I create objects in the NSView subclass and Draw them in draw() func.
I did some more test, to check how to use topLevelObjects.
I replaced IBOutlets by simple properties.
It works well in Xcode, but crashes the same in Finder. But I do think that's the direction to look at.

Code Block
final class KaraokeSongView: NSView {
var rootView: NSView!
var songTitleView: NSTextField!
var currentTimeView: NSTextField!
var songLengthView: NSTextField!
var songPositionView: NSProgressIndicator!
var playPauseButton: NSButton!
var dragDestination: KaraokeSongDragDestinationView!
var unpackProgress: NSProgressIndicator!
var showInFinder: NSButton!
var songDisplayView: NSImageView!
var songVideoView: AVPlayerView!
var volumeSlider: NSSlider!
var songUrl: URL!
var player = AVAudioPlayer()
var avPlayer = AVPlayer()
let formatter = DateComponentsFormatter()
var currentCdgPacket = 1.0
var timer: Timer!
var myArray : NSArray?
required init?(coder: NSCoder) {
super.init(coder: coder)
let myName = type(of: self).className().components(separatedBy: ".").last!
if let nib = NSNib(nibNamed: myName, bundle: Bundle(for: type(of: self))) {
nib.instantiate(withOwner: self, topLevelObjects: &myArray) // nil)
print("myArray count", myArray?.count)
print("myArray[0]", myArray![0])
print("myArray[1]", myArray![1])
if let topView = myArray![0] as? NSView {
print("topView 0", topView, topView.frame)
for newView in topView.subviews {
self.addSubview(newView)
print("newView", type(of: newView), newView.frame)
}
} else if let topView = myArray![1] as? NSView {
print("topView 1", topView, topView.frame)
for newView in topView.subviews {
self.addSubview(newView)
print("newView", type(of: newView), newView.frame)
}
}
// setup()
} else {
print("init couldn't load nib")
}
}


myArray contains 2 objects: NSApplication and the top NSView
But in any order, hence the need to test [0] and [1].

Here the output, showing we get all the objects. And some errors at the beginning.
We should now need to connect to properties in the class.

2021-03-14 17:09:02.287271+0100 BugCode[50871:3973074] CDN - client insert callback function client = 0 type = 17 function = 0x7fff322a4246 local_olny = false
2021-03-14 17:09:02.287323+0100 BugCode[50871:3973074] CDN - client setup_remote_port
2021-03-14 17:09:02.287352+0100 BugCode[50871:3973074] CDN - Bootstrap Port: 1799
2021-03-14 17:09:02.287502+0100 BugCode[50871:3973074] CDN - Remote Port: 41999 (com.apple.CoreDisplay.Notification)
2021-03-14 17:09:02.287545+0100 BugCode[50871:3973074] CDN - client setup_local_port
2021-03-14 17:09:02.287567+0100 BugCode[50871:3973074] CDN - Local Port: 24579
2021-03-14 17:09:02.292836+0100 BugCode[50871:3973128] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x60000023f9c0> F8BB1C28-BAE8-11D6-9C31-00039315CD46
myArray count Optional(2)
myArray[0] <NSView: 0x100625a90>
myArray[1] <NSApplication: 0x6000035000b0>
topView 0 <NSView: 0x100625a90> (0.0, 0.0, 490.0, 340.0)
newView NSSlider (448.0, 27.0, 24.0, 255.0)
newView AVPlayerView (0.0, 0.0, 432.0, 280.0)
newView NSImageView (0.0, 0.0, 432.0, 280.0)
newView NSTextField (431.0, 292.0, 41.0, 16.0)
newView NSTextField (18.0, 316.0, 416.0, 16.0)
newView NSProgressIndicator (53.0, 289.0, 372.0, 20.0)
newView NSButton (440.0, 0.0, 40.0, 25.0)
newView NSBox (5.0, 286.0, 465.0, 5.0)
newView NSTextField (6.0, 291.0, 41.0, 16.0)
newView KaraokeSongDragDestinationView (0.0, 0.0, 490.0, 340.0)
newView NSButton (438.0, 306.0, 49.0, 32.0)
myArray count Optional(2)
myArray[0] <NSApplication: 0x6000035000b0>
myArray[1] <NSView: 0x10062b660>
topView 1 <NSView: 0x10062b660> (0.0, 0.0, 490.0, 340.0)
newView NSSlider (448.0, 27.0, 24.0, 255.0)
newView AVPlayerView (0.0, 0.0, 432.0, 280.0)
newView NSImageView (0.0, 0.0, 432.0, 280.0)
newView NSTextField (431.0, 292.0, 41.0, 16.0)
newView NSTextField (18.0, 316.0, 416.0, 16.0)
newView NSProgressIndicator (53.0, 289.0, 372.0, 20.0)
newView NSButton (440.0, 0.0, 40.0, 25.0)
newView NSBox (5.0, 286.0, 465.0, 5.0)
newView NSTextField (6.0, 291.0, 41.0, 16.0)
newView KaraokeSongDragDestinationView (0.0, 0.0, 490.0, 340.0)
newView NSButton (438.0, 306.0, 49.0, 32.0)
2021-03-14 17:09:02.334430+0100 BugCode[50871:3973128] HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
2021-03-14 17:09:02.371983+0100 BugCode[50871:3973074] Metal API Validation Enabled


Hey, thanks for looking into this.

Yes the BugCode was just the bare minimum I needed to look into this issue. It won't be fully formed code, and yes there probably are some missing assets.

I've tried a couple of variants of nib loading code, but they all seem to give me that same error.

I haven't tried creating the view without it being backed by a xib file, but I'll give that a go and see what happens.

Thanks for your help.

I am pretty sure it will work without a xib.

xib solution must work, but you need to manage topLevelObjects. Which is not totally immediate…