Re: Strange controls behaviour in sheet modal window


Graham Cox
 

OK, if anyone’s interested, I figured this out.

This is in an ARC project, and it’s a memory management issue. The window controller was being returned by a class method that just alloc+initWithWindowNibName: ‘d it and returned it. The client code then invoked the method on it that displays it as a sheet.

The probem is that left no reference to the window controller, so ARC duly released it. The window itself was shown completely normally and displayed as a sheet, with all its controls fully working. The controls targetted the now-released window controller, but controls now use a zeroing weak reference, so that ended up as nil. That caused the controls to try and send the action to First Responder, which didn’t implement the action, so it just beeped.

Keeping a strong reference to the window controller for the duration of the sheet fixes the issue.

While I fully get this, I’m not sure if there’s a better way to handle it than having a temporary ‘strong’ property for the controller within the client object. Usually for dialogs like this, I don’t need such a property, and in manual retain/release land, I can make put a self-retaining behaviour around the document modal sheet operation of the dialog so that client code is spared the need for it. Obviously with ARC I can’t do that, so the onus is on the client code to do it. This actually makes the client code much MORE memory management aware with ARC than without! A bit ironic that.

Is there a better solution?

—Graham

On 5 Dec 2017, at 2:50 pm, Graham Cox <graham@...> wrote:

Hi all,

I have a problem with controls in a sheet-modal window.

The button control’s target and action are set up to call a method in File’s Owner, which is a NSWindowController subclass that owns the sheet. The sheet displays fine, and all the outlets are correctly set. The controls all appear normal and can be clicked. The target and action in the button’s cell appear to be correctly set (checking in -awakeFromNib). But when I click the button, I just get a beep, and the action method is never called.

The stack trace of the beep is:

#0 0x00007fff323c4937 in NSBeep ()
#1 0x00007fff3239079c in -[NSControl sendAction:to:] ()
#2 0x00007fff3239069f in __26-[NSCell _sendActionFrom:]_block_invoke ()
#3 0x00007fff323905a5 in -[NSCell _sendActionFrom:] ()
#4 0x00007fff323d1858 in -[NSButtonCell _sendActionFrom:] ()
#5 0x00007fff3238ee06 in -[NSCell trackMouse:inRect:ofView:untilMouseUp:] ()
#6 0x00007fff323d159f in -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] ()
#7 0x00007fff3238d8a4 in -[NSControl mouseDown:] ()
#8 0x00007fff32a88a01 in -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] ()
#9 0x00007fff32a85658 in -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] ()
#10 0x00007fff32a84904 in -[NSWindow(NSEventRouting) sendEvent:] ()
#11 0x00007fff328e5937 in -[NSApplication(NSEvent) sendEvent:] ()
#12 0x00007fff32147861 in -[NSApplication run] ()


I’ve made literally hundreds of sheet-modal dialogs over the years and have never run into this problem.

I’m showing the sheet using -beginSheet:completionHandler: , and as mentioned I’ve verified that all outlets, targets and actions appear to be set as expected. The sheet is made key as expected and the first text field is selected as initial responder.

Any ideas? This is on 10.13.1, Objective-C.


—Graham




Join {cocoa@apple-dev.groups.io to automatically receive all group messages.