4

I have an app that uses multiple Modal Sheets for data entry. The methods in opening the modal sheets worked fine, and still work fine, but they have been deprecated and I fear they will soon not work with future releases of Xcode. Here, Apple points out how to use modal sheets,

    - (void)showCustomSheet: (NSWindow *)window

// User has asked to see the custom display. Display it.
{
    if (!myCustomSheet)
//Check the myCustomSheet instance variable to make sure the custom sheet does not already exist.
        [NSBundle loadNibNamed: @"MyCustomSheet" owner: self];

    [NSApp beginSheet: myCustomSheet
            modalForWindow: window
            modalDelegate: self
            didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
            contextInfo: nil];

    // Sheet is up here.
    // Return processing to the event loop
}

but with the release of Xcode 5.1, they identify that the loadNibNamed method has been deprecated and that we should use a similar function referencing top-level objects.

The problem I am having, is changing this:

[NSBundle loadNibNamed:@"OrderDetailsWindow" owner:self];

into this.

NSArray *array;
[[NSBundle mainBundle]loadNibNamed:@"OrderDetailsWindow" owner:self topLevelObjects:&array]; 

This method call does in fact open the modal sheet. However, at the end of my method that opens the modal sheet, Xcode hangs-up with this error.

0x7fff8c33b097:  andl   24(%r11), %r10d    Thread1: EXC_BAD_ACCESS (code:EXC_I386_GPFLT)

I'm not sure what this is telling me. It doesn't give me any information in the debug area. Could this have to do with the topLevelObjects array not being released properly? Any thoughts on how to make this work a little more smoothly? Apple's out-of-date library is driving me nuts!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Breeze73
  • 43
  • 1
  • 4
  • You are using Xcode 5.1? – El Tomato Oct 26 '13 at 01:37
  • 2
    If you are using Xcode 5.1 then you must work at Apple. The rest of us are using Xcode 5.0.1. FYI - your question has nothing to do with Xcode. Anything that is deprecated has to do with the version of the API of the Cocoa framework. – rmaddy Oct 26 '13 at 03:20
  • Look at [this](http://stackoverflow.com/questions/19602390/trying-to-replace-deprecated-loadnibnamedowner/19602670#19602670) recent question, you may have the same issue. – CRD Oct 27 '13 at 02:34
  • Please refer this link http://stackoverflow.com/questions/19608665/how-do-i-open-an-nssheet-in-mavericks – Hussain Shabbir Oct 27 '13 at 10:30
  • Lol.. No, I don't have 5.1. My typo. I have 5.0.1. too. I looked at both examples, and tried incorporate some of the suggestions, but I'm still having the same issue. I think the issue might be some thing along the lines of sheet ownership. The modal sheets are run completely within their own classes. When a button is clicked (or a double-click in some areas) on the main window, that fires the modal sheets to open. – Breeze73 Oct 27 '13 at 18:27

2 Answers2

4

Yes, Apple's documentation is a mess. The "Sheet Programming Topics" document has not been updated since 2009.

You don't show the full code after the change but my guess is that your problem is with the memory management of your NIB's objects.

From the documentation of the new loadNibNamed:owner:topLevelObjects:

Unlike legacy methods, the objects adhere to the standard cocoa memory management rules; it is necessary to keep a strong reference to them by using IBOutlets or holding a reference to 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.

You have the NSArray that holds the top level objects inside your method. Once the execution leaves this method, the NSArray will be derefernced and released and so are all your top level objects if those are not strongly referenced anywhere else.

You need to either connect your top level objects in the NIB to outlets in your Window Controller or keep the NSArray as a member variable of your Window Controller instance, so it doesn't get released once your sheet showing method exits. And make sure that myCustomSheet properly declared and connected from the sheet's NIB.

Also, [NSApp beginSheet:] is deprecated as well, you now call beginSheet on an instance of NSWindow.

danielv
  • 3,039
  • 25
  • 40
  • Good response. I think this is exactly the problem I'm having. I'll mess around with it and see if I can get it working. – Breeze73 Nov 02 '13 at 03:11
0

I always use a NSWindowController subclass with a custom delegate for my sheets:

From the window that wants to display the sheet:

_myModalController = [[MyModalController alloc] init];
_myModalController.delegate = self;
[_myModalController beginSheet:self.window];

Then within the modal window controller, I have:

- (id)init {
    self = [super initWithWindowNibName:@"MyModalWindow" owner:self];
    return self;
}

- (void)beginSheet:(NSWindow *)mainWindow {
    [NSApp beginSheet:[self window]
       modalForWindow:mainWindow
        modalDelegate:self
       didEndSelector:@selector(_didEndSheet:returnCode:contextInfo:)
          contextInfo:nil];
}

- (void)endSheet:(NSWindow *)mainWindow {
    [NSApp endSheet:[self window]];
    [[self window] orderOut:mainWindow];
}

This appears to avoid the whole issue of loadNibNamed: becoming deprecated.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • Not all loadNibNamed forms are deprecated, need to use the current one. [NSApp beginSheet] and [NSApp endSheet] are deprecated as of 10.9 – danielv Oct 31 '13 at 15:50
  • @danielv Hmm, didn't see that. No warnings from Xcode though (however my min-macosx-version is 10.7, so perhaps that's why). I wonder what else I'm using has been deprecated... – trojanfoe Oct 31 '13 at 16:01
  • @danielv Yes, I'm using 10.9 SDK. What's worse is that I need to keep my existing method for 10.{7,8} and the new method for 10.9+. – trojanfoe Oct 31 '13 at 16:09
  • Guess those are not "formally" deprecated yet. From NSApplication.h: "These methods are deprecated in 10.9 and will be formally deprecated in the following release.". Seems like "not formally" deprecated means there are no warnings? – danielv Oct 31 '13 at 16:17
  • @danielv Yeah I don't think it will be a problem; that delegate method hardly does anything anyway so the code won't be complicated. Thanks for your help - it feels like I was the one who asked the question ;-) – trojanfoe Oct 31 '13 at 16:18
  • With this answer and the above answer from danielv, I think I should be able to figure it out. I'll post back if I run into any snags. – Breeze73 Nov 02 '13 at 03:14