I have a Cocoa app with a custom, multi-step account setup that I implemented as a custom modal dialog with a set of views.
The problem is that the background operations (fetching a URL) seem to get stuck. I assume that this is because the application is in a modal mode.
Here the code to start the modal dialog:
[NSApp beginSheet:accountSetupController.window modalForWindow:self.window
modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
[accountSetupController beginAccountSetup]; // this later launches the background operation
[NSApp runModalForWindow:accountSetupController.window];
NSApp endSheet:accountSetupController.window];
First of all, is my assumption correct? Is there a way to have the background operation proceed even if the application is running modal?
The actual background operation is not under my control. It is an external API that takes a completion block.
Take a look at the "discussion" section of your call to [NSApplication beginSheet: modalForWindow: ...]:
Discussion
This method runs the modal event loop for the specified sheet
synchronously. It displays the sheet, makes it key, starts the run
loop, and processes events for it. While the application is in the run
loop, it does not respond to any other events (including mouse,
keyboard, or window-close events) unless they are associated with the
sheet. It also does not perform any tasks (such as firing timers) that
are not associated with the modal run loop. In other words, this
method consumes only enough CPU time to process events and dispatch
them to the action methods associated with the modal window.
To me, this means that background threads and tasks aren't running while this modal session is going. I've run into this problem before with my own modal dialogs trying to access web servers (for registration purposes, if I remember correctly).
The best solution is to not use modal dialogs if you need to talk to a server asynchronously. If you must use modal dialogs, try to do your communication between modal sheets (i.e. when the user hits "submit", end the sheet and do the server chatting, then bring up the next sheet for the next step).
Related
I am writing an application that does a blocking operation on the main thread using dispatch_sync_f when toggled (input from keyboard). I have a while loop inside the function that was passed to dispatch_sync_f that performs some routines. To ensure window events are processed while in this loop, I wrote the following and pass it along.
event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES];
[NSApp sendEvent:event]
However, when I try to go fullscreen (green button) it is stuck until this blocking function is untoggled. I thought I was passing along all events any keyboard/mouse input to the window is processed. But going fullscreen may not have been an event in this case. Is there a way to detect fullscreen event and pass it to the window while the main thread is blocked?
I have a UIButton that trigger the IAP process. There is some time (2/3s or more if internet connection is bad) before an alert view is displayed (either asking for id and password, or the confirmation one). So one may click several times, thinking that the button is not working. And then you get as much alert view in a row as times you clicked and they are shown even if I quit the app and I'm on another meanwhile. That's pretty annoying.
My solution so far is to set a boolean as property of the UIviewcontroller. If it's false, click does nothing, else click trigger payment process. I set it to false on first click and in viewwillappear i get it back to true. The problem is that to be able to click the button again you must leave view and come back to it. That's not cool...
So here is what I'm looking for ideally : a function that is triggered as soon as any alert view of any kind is shown or dismissed. Show is better because i could use that to stop an eventual activity indicator I'd like to add too.
Thank you for you ideas.
Don't base it on the alert view being shown (you can't anyway). Instead, when the button is pressed, disable it or hide it (and show your activity indicator). When you start the purchase, add your controller as the delegate. Use the delegate methods to update the UI to enable / show the button (or remove it all together if more appropriate) when you get the callbacks which tell you the purchase is complete / failed.
Is there any way, when a UILocalnotification is displayed as an alert, for there to only be one action button displayed, rather than both "Close" and "Launch"?
Assuming there is no way, I can change the second action button to say "Continue". I want to be able to register in my app that they did press "Continue" but I don't want the app to actually launch. Is this possible?
It's not possible within current SDK, unfortunately. The push notification alert can have only two actions – either it's cancelled and your application is not notified, or your application is being brought to foreground to handle the notification.
I have a menu which I'd like to have automatically hide if it's inactive after a certain amount of time. This menu is composed of a hierarchy of UIViewControllers, which present various different views.
I'm thinking along the lines of running a timer, which invalidates and starts over whenever there's a touch.
Is it possible to catch all touch events in a set of UIViews? Perhaps just keep a boolean lying around and use the main UIWindow to catch touch events?
EDIT:
My app is a kiosk app of sorts, with a main screen and a menu. When the menu is up, I want it to run an auto dismiss timer, which resets after any touch in the entire menu screen. The menu is displayed over the entire screen, modally.
One way to be sure is to subclass UIApplication and override - (void)sendEvent:(UIEvent *)event method, every touch event happening in your app goes through this method and you can check the UIEvent type to see if it's UIEventTypeTouches and reset the timer.
Another way to do this simply involves adding a transparent layer over whole user accesible UI and override hitTest:withEvent:.
You can have an invisible view on top of your modals view controllers, and put have either a gesture recognizer on it which can start a timer, either a
-touchesBegan:withTouches
method, and then send to the .nextResponder the same method.
Issue1:
I want to show an alert window or message box before the Main Window of the Application is launched. When im using the NSRunAlertPanel() it is not showing the alert window.It is directly launching the Application's Main Window.
Issue2:
I want to create an Modal (login dialog) and message boxes in an thread spanned from the main thread.
Its urgent
So, Kindly reply soon...
Thank You Pradeep.
Issue2: I want to create an Modal (login dialog) and message boxes in an thread spanned from the main thread.
In Cocoa, nearly all UI code must run on the main thread. There are a few limited, well-defined exceptions (e.g., the opt-in threaded drawing introduced in Snow Leopard), but the general rule is to not run UI code on another thread.
Besides, you don't need a thread anyway. It's not like the modal dialog is going to be computationally intensive.
Send NSApp a runModalForWindow: message, passing the dialog. This will run the dialog on the main thread, blocking the rest of your UI. If you don't want to block the UI (and you generally shouldn't), just make it key and order it front, like usual.
What you can do is:
uncheck the "Visible at launch" option for your main window in Interface Builder.
start your application as usual
decide whether or not to show the modal dialog
invoke "orderFront:" message of the main window.