The screen becomes blurred like UIAlertview is popping very slowly, whenever my app posts tweet requests in iOS5. How do I fix that?
after the completion of request I used [alertView show] method in the the request handler block of TWRequest which I assume was called in different thread and was causing the issue. Calling that method in main thread solved the problem.
[alertView performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO];
Related
I'm developing a game that uses cocos2d-x, I'm having a problem on old devices such as ipad 1 where large scene takes a lot of time to load.
so the scene transition can take a few seconds, therefore I tried to implement a "busy" animation between scene transitions while the new scene is being loaded.
I implemented this using MBProgressHUD on IOS and ProgressDialog on android.
I decided that I don't want to start showing this animation immediately, instead I could schedule the animation to start 1-2 seconds after the scene transition starts, so that on newer devices the animation will not be shown at all.
Initially what I did was this:
- (void) showProgressDialog: (int) runWithoutDelay
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showProgressDialogAfterDelay) object:nil];
shouldShow = YES;
if (runWithoutDelay){
[self showProgressDialogAfterDelay];
}
else{
[self performSelector:#selector(showProgressDialogAfterDelay) withObject:nil afterDelay:delay];
}
}
- (void) showProgressDialogAfterDelay
{
if (shouldShow){
isShown = YES;
[progressHUD show:YES];
}
}
and if I pass the scene transition part I would just set shouldShow flag to false and won't start the animation.
The problem is that because cocos2d-x scene transition is done in main\ui thread sometimes instead of calling the show method after 2 seconds it takes up to 6-8 seconds for it to be called and sometimes it even gets called after I set my flag to false.
As I understand it happens because performSelector (and so is NSTimer which I also tried) both run on the same thread by placing the call in the thread run loop queue.
I needed something like performSelectorInBackground that takes delay, so I tried using dispatch_after (even though I still haven't figure out how this could be canceled, as I need to cancel a previous schedule when I create a new one) this looked more accurate according Xcode's logs but even though the logs said that the method was called exactly 2 seconds after being scheduled the time would take 5-8 seconds to show and sometimes would not show at all.
As I understand it, and correct me if I'm wrong, this happens because MBProgressHUD changes to UI must happen on main\UI thread so even though I call [ProgressHUD show:YES] on a background thread the actual update of the UI is scheduled to be executed somehow on the main thread and because of it being stuck on cocos2d-x stuff it only starts to show after that, when the scene transition is completed and its too late.
is there any way around this problem? can I somehow schedule it to start with a delay but have it display right when I want it?
What I don't understand is why if I start it with no delay the animation works smoothly without being stuck even though the main thread is busy with cocos2d-x processing.
I‘ve managed a way around this somehow!
Create a normal method where you will call the progressHUD and call the second
Create the second method where you do the time consuming stuff (loading views)
Perform that method on the main thread
Sample:
-(void)callHUD {
[progressHUD show];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelectorOnMainThread:#selector(loadView) withObject:nil waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[progressHUD dismiss];
});
});
}
-(void)loadView {
//Perform your segue or transition which needs to load
}
Hope that could help you a little.
i am working on a iOS application with accessibility support. At some point in my application flow, i present an alert view. After presenting the view, i want to focus on the view using UIAccessibilityPostNotification, however the notification seems to get overridden.
[alertView show];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,alertView.somesubView);
However i do not see the effect of this notification. The accessibility focus goes to some other view object in the background.
However, when i use dispatch_after with 0 delay, it works
[alertView show];
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW,0 * NSEC_PER_SEC);
dispatch_after(delay,dispatch_get_main_queue(), ^void(){
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,alertView.somesubView);
});
Can someone explain what is the reason ?
You've stumbled upon the standard solution. It's likely that the user interface or accessibility hierarchies may not have updated, yet, to reflect the presence of the alert view. An async dispatch to the main queue ensures that all other enqueued tasks, including any updates to user interface or accessibility state, execute before the notification is posted.
That said, VoiceOver should focus alert views automatically. You might want to investigate what interfered with this behavior in the first place.
I'm stepping through some code in lldb, and I come across [alert show]. I step across it, nothing happens, then I continue and the alert pops up, presumably triggered sometime later. Just for curiosity's sake, when does that show message actually get sent to the operating system? What's really going on when I step over [alert show]? The documentation doesn't address it.
UIKit and core animation changes are processed and applied as part of the main run loop. When you call [alert show] the appropriate view hierarchy changes, frame changes, animations etc. are queued up in the system. When you return from your code the runloop will process these as part of the core animation transaction internals and you will see the changes on screen.
I am getting the following error intermittently when a call is made to display an action sheet.
Assertion failure in -[UIActionSheet showInView:]
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: view != nil'
Now in this case I've not changed screens. The UIActionSheet is presented when a local notification is fired and I have an observer call a local method on this view as such: I have the property marked as strong. When the action sheet is dismissed I also set it to nil. I am using a story board for the UI. It's fairly repeatable to crash it, perhaps less than 5 tries. (Thankfully I have that going for me). Any suggestions what to try next? I'm really pulling my hair out on this one. Most of the issues I've seen on this topic are pointing to the crash occurring once the selection is made. In my case it's at presentation and intermittently. Also for what it's worth, this particular view is several stacks deep in an embedded navigation controller. Home>tableview>detail select>viewController in question. This same issue occurs so far in testing on iOS 5.1 and iOS 6. I'm presuming it's something to do with how the show InView is being targeted.
self.actionSheet = [[UIActionSheet alloc]
initWithTitle:#"Select Choice" delegate:self cancelButtonTitle:#"Not Yet" destructiveButtonTitle:#"Do this Now" otherButtonTitles:nil];
[self.actionSheet showInView:self.parentViewController.tabBarController.view];
Based on your code, it would seem that self.tabBarController or self.tabBarController.tabBar are not set when this is called.
Try using:
[self.actionSheet showInView:self.view];
Edit: fixed error
Edit 2: Making the action sheet appear on top of a tab bar
[self.actionSheet showInView:[[UIApplication sharedApplication].delegate window]];
The answer to the problem was that I was not removing an NSNotificationCenter observer. It only became obvious when the change was made recommended by #zsnow which resolved the crash but resulted in duplicated UIAlertSheet dialogs being presented.
In my particular case adding the following resolved my issue. Thanks for everyone's help. The suggestions got me close enough to cross the finish line.
-(void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I have the following code in viewDidLoad, which works properly on iOS 4.3, but it hangs on iOS 5/5.1. On iOS 5/5.1, the alert dialog is shown but can not be dismissed, the UI thread freezes, the OK button just can not be clicked.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.webview stringByEvaluatingJavaScriptFromString:#"alert('HELLO WORLD!')"];
});
});
Is this a bug?
After test, I consider it as a Bug, and changing code to use
[webView performSelectorOnMainThread:#selector(stringByEvaluatingJavaScriptFromString:) withObject:js waitUntilDone:NO]
will solve it.
Try it in - (void)viewDidAppear:(BOOL)animated instead
Why are you using GCD at all here?
Remember that in GCD there is no guarantee which thread your code will called on, regardless of queue. My guess is that your DISPATCH_QUEUE_PRIORITY_DEFAULT code happens to be running on the main thread, which is then triggering a deadlock on your dispatch_sync() call. This could be verified by examining your thread states in the debugger or Instruments.
Which gets back to my original question: what do you get by doing these convolutions instead of just calling the method directly on the main thread? You are going to block either way.
You can also change your dispatch_sync() to dispatch_async() - that should also suppress a deadlock, but should only be done if you have other concurrency needs and don't need a background thread to block.
Try
dispatch_async(dispatch_get_main_queue(), ^{
[self.webview stringByEvaluatingJavaScriptFromString:#"alert('HELLO WORLD!')"];
});