applicationDidChangeScreenParameters and [NSWindow orderOut:] - objective-c

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.

Related

Modal NSSavePanel disappears after animating in when begun from a completion block

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.

iPad app freezes during NSOperationQueue

I have a problem with an app where I implemented an NSOperationQueue.
It seems that pressing the close button of the iPad makes the UI freeze. The app itself is still running in the background, the UI is updated, it's just that it won't answer to touches or rotation anymore and it doesn't get closed as it should be.
I have an update module that downloads quite a long list of xml files and saves them on the device. The operation queue has a MaxConcurentOperations value of 2.
Usually everything works fine, the app runs fine and dandy, responding to my touches and rotation UNTIL I press the device's button. After this, the UI simply freezes. The progress is still updated (an UILabel), recurrent animations are still displayed, but the app is not closed until all the operations are done.
I'm not calling waitUntilAllOperationsAreFinished on my queue so I don't know what might be causing this.. So far, I've only made tests on a first generation iPad, with iOs 5.0
If anyone can provide me with some tips, I'll really appreciate it. If necessary, I can post the NSOperationQueue and NSOperation class codes, but somehow I have the feeling this about me approaching this wrongly, and not about a faulty line of code
[edit]
I also use a timer to periodically check on the download status, but I noticed that not calling the timer doesn't eliminate the problem
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(xmlDownloaded) userInfo:nil repeats:YES];
[edit2]
After some further research, I made sure that my operations are concurrent and just to be sure, I changed the way I added my operations to the queue.
Instead of
[downloadQueue addOperation:op];
I added them to a mutable array called "operations" and in the end I used
[downloadQueue addOperations:operations waitUntilFinished:NO];
but my app still freezes when I press the close button...
Wild guess, you are locking the main thread waiting for your operation to complete / you are destroying your operation delegate on viewWillDisappear?
It seems there was another function causing this, even though I don't understand why...
I had a label animation
CABasicAnimation *fadey = [CABasicAnimation animationWithKeyPath:#"opacity"];
[fadey setToValue:[NSNumber numberWithFloat:0.35f]];
fadey.repeatCount = HUGE_VALF;
[fadey setAutoreverses:YES];
[fadey setDuration:0.6f];
This small function was causing the app to wait until all the operations were finished in order to close the app. The weird part is that the function was not even called in with the NSOperations, but before them
Again, I have no idea why... everything breaks when I press the close button, otherwise there are no problem. So if anyone else runs into a similar issue, it might help to check for some repeating animations

Time limit for an IBAction?

It may sound as a dumb question. In fact, I am still thinking if that might be the cause but working with XCode and having set iOS 4.3 as my Deployment Target and iPad as my Device I am getting an unexpected error.
While running my app through the Simulator I can get it working. But when I run it through my iPad a single IBAction, fired when user taps an UIButton, that takes almost 4 minutes is not completing. In fact it's getting stopped at the same point, in a for loop.
I searched for memory leaks using XCode and it didn't find any, therefore I'm asking if there's a time limit for IBActions. I read there are 10 minutes limit for methods in background but I didn't find anything related to IBActions in foreground yet.
I think the user gets tired of waiting for a response long before the system. Normally, a button press or similar should finish after one second at most (well, maybe 1.5s), or the user thinks that the system is "slow".
I would make sure that you have your button outlets properly hooked up. It is possible that it just isn't throwing the exception so you get a slow system. Put NSLog displays in your IBAction method and make sure it is executing it properly. You should be able to track it back to figure out what is going on.

Cocoa program exits with no crash

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.)

Is there a function for "processing messages", i.e. updating screen, responding to accumulated user input

I have encountered a strange bug in my application, and I am trying to debug it using step execution.
However it seems that things on an iphone often do not happen as synchronously as I would like, for example when I step-over this line
[self.view addSubview:FinndomoEmbeddedMWView.view];
nothing happens in the emulator.
If I just let the program run, the view is added and the screen changes as it should.
So I am guessing, addSubview does not do everything related to adding a view, it just sort of starts the process, and then it is completed later.
I don't know if there are message queues on ios similair to winapi, but there must be something like that, so is there a function for "processing all accumulated messages". I would then like to call this function after my addSubview and actually see the things change in the emulator while I debug, not when the program is running.
And I experience this not only with addSubview, so I want to have a general solution for things like this.
Sat yesterday and found out the answer:
NSDate *dtr = [[NSDate alloc] initWithTimeIntervalSinceNow:0.5];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:dtr];
This is sort of what I wanted. As you can see, this particular code may end up waiting for 0.5 seconds if there are no more events, and if there are events pending, it is only processing the first one and then returns (according to documentation).
But that could be avoided of course, this is just an example, if anyone will want the same thing. In my case there was only 1 important event, and so the provided snippet worked.
The short answer is no.
Cocoa is event-driven.
The core of each app is the event loop. On each pass through the event loop, the app handles events added to the event queue. Updating the screen is one such event.
Thus, changes to screen display don't take place until after your code returns, on the next pass through the event loop.
For debugging purposes where you want to figure out what's happening line-by-line, you need to either use the debugger's facilities, or add NSLog statements to your code.