I managed to create a bug where a cocoa program is exiting.
-[NSApplication terminate:] is apparently not called.
Nor is -[NSException init].
There is no crash. What I am seeing in gdb is that exit() is being called directly from NSApplicationMain without going through the normal [NSApplication terminate] path.
Any ideas about how to debug this and/or how this (seemingly "impossible" behavior) could happen?
Thanks in advance from a cocoa newb.
I would start with judicious use of breakpoints. Narrow it down to the last place where your code is seen before the faux crash and then start looking around that area for memory issues. Whenever I have really strange behavior, it's almost entirely due to a strange memory bug.
There are few remaining routes that would cause your application to voluntarily exit without going through the normal [NSApplication terminate] path.
Try setting a breakpoint on "stop:". I suspect somehow, perhaps an inappropriately named performSelector call? Or a badly named IB connection, you are calling this method, which is documented to exit from the main event loop.
After mulling this over I guessed that I was doing something wrong "in the big picture". So, "in the big picture", what I was doing is calling a modal dialog (by loading a window nib, showing the window and then using [NSApplication beginModalSessionForWindow]...[NSApp runModalSession]... and upon close [NSApp endModalSession]. This has worked for me in other chunks of code no big deal. The critical difference was that this modal window was being loaded and run out of another class's awakeFromNib.
I wrote a simple app that will reproduce this behavior. So what happens is that the modal dialog loads happily and when you close the modal window not only does it close but the app exits. I imagine that this is an "as designed" behavior. I was reading up in apple docs to see if I could understand why this was so but I am will muddled on it. I surmise that somehow my dialog's modal event loop has hijacked the app's event loop so that when the dialog ends so does the app.
If anybody has a better understanding of this mistake please feel free to enlighten us...
Thanks to all for reading and suggestions.
PS -- I changed my code to use [NSApplication runModalForWindow:] instead of the modal session calls and all is well (I think). (Using the modal session would allow me to launch a web browser from a modal dialog -- while runModalForWindow does not -- but in this case I don't need that functionality.)
Related
G'day!
Note: Minimal example linked below. I'll refrain from longish code excerpts and rather explain the problem concisely.
I am in the process of updating an old (but small) Cocoa application to current APIs.
One of the places that looked easy enough at first: When the user tries to close the application window with unsaved changes, the app first displays an NSAlert asking "Save your stuff?". If that is confirmed a modal NSSavePanel is shown. In the original code they were opened via, respectively:
beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:
beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:contextInfo:
Current Cocoa API uses completion blocks and thus the alert prefers to be shown via beginSheetModalForWindow:completionHandler:. So I moved the code from the didEndSelector into the completionHandler.
Unfortunately the modal NSSavePanel does animate in but disappears immediately together with the application main window if it is shown from the NSAlert's completion block. If I switch the alert back to the didEndSelector I can show the NSSavePanel either selector-basedly or completion block-ly just fine.
Here's the NSAlert's completion block that forwards to the disappearing save panel.
I have thought about threading issues. All of this is happening on the main thread. Maybe there's something subtle going on with run loop modes that I'm missing?
The minimal example is available over on GitHub. You can switch between selectors and blocks with defines in AppDelegate.h. All the interesting code is in AppDelegate.m. (Unless the problem is somewhere else...)
As #Willeke pointed out this wasn't an overly mysterious issue with threading and whatnot. No. It was just me having looked at the code way too often over the course of days.
The solution is simple:
The breaks in the switch statement in confirmUnsavedChanges are missing.
So I'm trying to convert a project to ARC. The first attempt, I just converted everything and I had this problem on one of my views, it just hangs. I cannot click on any UI element, and nothing is printed to the console, and it doesn't crash. It just sits there.
So in order to start troubleshooting it, I converted all the simple classes and viewControllers, and then for some of the more complex model classes and UIViewController classes, I set the compiler flag for -fno-objc-arc. My app runs better, but it still just gets in this state where it hangs. I've never seen this on it prior to converting to ARC. I was wondering if anyone else has had this problem and what I can do to troubleshoot it. Thanks~
I would press "pause" in the debugger and look at the call stacks for all threads in your app. This can point out why your app is locked up.
In my application, it's necessary that the application's window close upon the system changing resolutions. While it's easy enough to implement - (void)applicationDidChangeScreenParameters:(NSNotification *)notification, I've run into an odd bug.
Strangely, my window seems unable to respond to orderOut: calls when this notification fires. It IS firing, because my NSLog works fine and I even tried dropping in [NSApp terminate:nil], which also works fine. There are other unrelated methods when that order the window out and they work without problems which is what makes it strange.
Is there are reason that my window is unable to close in these circumstances? What could cause this?
Can you just delay the close until the next run through the event loop? To do this, use ‑performSelector:withObject:afterDelay: with a delay of zero.
I have a multi-threaded Cocoa app that processes images. The program has a progress bar and some text showing how far along the process is. This all works great. However, sometimes the interface will just freeze up and everything will stop updating. The progress bar stops moving, and the text stops updating in the percentage counter. However, the actual process is still working! I have an NSBeep() that fires when the program is finished, and I still hear that even though the UI is no longer being updated. It's as though the UI just disconnects from the code.
Another weird problem is that sometimes the NSOpenPanel that opens when the user wants to choose a file will just be a white void. I declared the NSOpenPanel (I'm using [NSOpenPanel openPanel]) in the main thread, which helps (I tried retaining it at first, but that didn't work). I don't know if this is related, but any ideas would be appreciated!
I am using Xcode 3.1.1 (GCC 4.2) on Mac OS X 10.5.8.
You're trying to manipulate the UI from other threads. As stated in the docs, AppKit is generally not thread-safe and you should interact with your GUI on the main thread. See -performSelectorOnMainThread:withObject:waitUntilDone:.
I get a crash in WebEditorClient::clearUndoRedoOperations which is trying to access -[WebView(WebViewEditing) undoManager] when I close the main window of an NSDocument that contains a webview with a text editor in it. It only happens when there is an undo-able state. Seems like a bug in Cocoa, but I might be doing something wrong. Any ides why this might be going on? The web view is in a nib and not created programmatically, so I'm not sure what I can do to even begin fixing this.
Well, removing it from superview prior to calling close on the document seems to have fixed it. Still, that doesn't explain what was going on, but just putting it here in case other people have this problem.