motionEnded works fine until I click a link in a webView - iphone

I'm using this code to do shake detection, and for the most part it works fine:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventSubtypeMotionShake) {
if ( event.subtype == UIEventSubtypeMotionShake )
{
NSLog (#"Shake Called");
}
}
I believe for this to work, I also needed to use these, which I have:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewDidDisappear:(BOOL)animated {
[self resignFirstResponder];
[super viewDidDisappear:animated];
}
This all works great, and motionEnded is called every time I shake, until I click through a link in a webView on my program. I can scroll up and down in the view and shake still works, but as soon as the view loads a new page, motionEnded stops being called when I shake. This occurs both in the simulator and on a real device (iPhone 3G, iOS4). From my limited understanding, I believe it has something to do with first responders, but I could be wrong there!

I have managed to answer my own question. For the reference of others who may have similar problems, the issue is that the viewController stops being the first responder once you click a link in a webView (or edit a text box, or some similar action). To fix the issue in my case, the answer was to make the viewController the first responder again after the new page loads:
- (void)webViewDidFinishLoad:(UIWebView *)nameOfWebView {
[self becomeFirstResponder];
}

I have the same problem, but becoming first reponder when web view finishes loading doesn't solve it for me. I know webViewDidFinishLoad gets called when a new page has been loaded, and I also know motionEnded gets called when I focus the web view by tapping it and then shaking or simulating shake.

Related

i need to reset the first view with a button press

on an app that i am creating, you need to slide a square through a maze and if it touches the wall, it goes to another screen telling you that you lose. However, when you hit the reset button, it goes back, and the square is in the exact same spot as where it touched the walls. Is there any way that i can press the button and have the square go back to start at the same time? Any feed back is appreciated! Thanks. (By the way, i am using Xcode.)
Here is the code for the button in the .h file:
- (IBAction)retry:(id)sender;
and here is the code for the .m:
- (IBAction)retry:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
Use viewWillAppear to reset your views
-(void) viewWillAppear: (BOOL) animated {
}
Call your initial method on buttonPressEvent.
- (IBAction)retry:(id)sender {
[self viewDidLoad];
}

cocos2d: animation stopped. Integrate Cocos2D and UIKit

I already integrate Cocos2D and UIKit.
I have the navigation among the views and the first time that I open the cocos view, it works.
But when I return to my main menu, the log console displays:
cocos2d: animation stopped
After that, if I try to get in to the cocos2D view again, the animation does not start.
What can I do to solve this?
I followed this tutorial but it don´t help
http://www.raywenderlich.com/4817/how-to-integrate-cocos2d-and-uikit
There have been issues regarding this. There was a similar discussion in another SO Question.
Whenever I want to include UIKit elements, I tend to do it the other way round.
With the CCUIViewWrapper code at: https://github.com/splhack/CCUIViewWrapper
This maybe be different depending on the version of cocos2d you are using, but stopAnimation should be being called on CCDirectorIOS.m:viewDidDisappear and startAnimation should be being called on viewWillAppear. So I would set breakpoints there to make sure it is being called on. And if your -(void) mainLoop:(id)sender is running.
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self startAnimation];
}
-(void) viewDidDisappear:(BOOL)animated
{
[self stopAnimation];
[super viewDidDisappear:animated];
}
If you want to investigate further the mainLoop calls drawScene and if it is not isPaused, then the CCScheduler will update the CCActionManager which runs all of the animations.
Hope this helps.

Why shake doesn't work when the screen is off on iPhone?

I am playing an audio file in the app, so it doesn't turn off when the phone is locked and the screen is off.
However when I want detect shake it does not work.
It works fine when the app is open and when the screen is locked (not off). The app is definitely running because the logs are working fine.
Any idea?
I use the following code:
-(BOOL)canBecomeFirstResponder {
//make it respond to shake events
return YES;
}
- (void)viewDidAppear:(BOOL)animated {
//make it respond to shake events
[self becomeFirstResponder];
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventSubtypeMotionShake) {
NSLog(#"Shake detected");
}
}
Monitoring the accelerometer causes extra power consumption by the phone, so it is disabled while the phone is locked. I don't believe there is a way around this.
This would help you.
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
This wont let the screen turn off.
Hope this helps.
EDIT:
But Even I feel the same as Akshay does. That it is not possible to capture UIEvent when screen is off.
I don't think you can capture UIEvents when the screen is off.

Detecting hits in UIScrollView while still letting it do it's thing

Is there a simple way to detect if someone touched a UIScrollView without having to disable user interactions?.
I know this has been answered a few times before, but every answer I find is somebody wanting to detect hits in an image. I don't have an image. What I do have is a scroll view with a number of text fields embedded in it. They used to be inside a UIControl, from which I could detect a touchDown and call resignFirstResponder on all my textfields (for when the keyboard is up). But when they are in a UIScrollView, I can't seem to find a simple way to do this.
I don't really want to have to write code to do the scrolling myself, which is what I assume I have to do if I disable user interactions and grab the touchesBegan message. But I may be wrong. I'm still a little new at this, but this is the first time I haven't been able to figure out the answer by reading the code doc and googling ...
Thanks for any help,
J
Override touchesBegan, do your processing, and call the super implementation so that the scroll view still gets the message.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//call resignFirstResponder
[super touchesBegan:touches withEvent:event];
}
Ok, now I feel a little silly answering this myself. I'm sure the other suggested answer would have worked also, but I found something else while browsing in other topics which totally fixed this for me.
I added this to my viewDidLoad:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(backgroundTap:)];
[scrollView addGestureRecognizer: singleTap];
Where backgroundTap is
- (IBAction)backgroundTap:(id)sender
is the function I was originally calling from touchDown in UIControl to resign all keyboard firstResponders.
This works perfectly and adds very little code. And I DON'T have to disable user interactions! Yay!
Thanks all for your comments and help.
J
I fiddled with this for a while, and found that simple touchesBegan and touchesEnd type stuff didn't really work.
They don't work because because of the gestures. For example touchesEneded never fires when you swipe to scroll (at least not in the UIScrollView). So while you can detect when a touch event starts, you'll never know when it ends.
I wasn't real keen on including a gesture recognizer for simple stuff and discovered that you can find out about the state of the scrolling better from interacting with the UIScrollView directly.
And it's not that painful. Just add the protocol, then add the functions you need for detection.
In the view (class) that contains the UIScrolView, add the protocol, then added any the functions from here to your view (class).
Example:
// --------------------------------
// In the "h" file:
// --------------------------------
#interface myViewClass : UIViewController <UIScrollViewDelegate> // <-- Adding the protocol here
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView;
// --------------------------------
// In the "m" file:
// --------------------------------
#implementation BlockerViewController
UIScrollView *scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(#"end decel");
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(#"end dragging");
}
// All of the available functions are here:
// https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html

"wait_fences: failed to receive reply: 10004003"?

I get this cryptic error the first time (and only the first time) my view is loaded due to the following line of code:
- (void)viewWillAppear:(BOOL)animated
{
[textField becomeFirstResponder];
}
There is a noticeable (~3 – 4 second, even on the simulator) delay due to this that makes my app feel unresponsive. Does anyone know how to fix this? I can't find any documentation on it on Apple's site, or any solutions here or on Google.
Strangely, the opposite situation happens if I put the line in -viewDidAppear: instead of -viewWillAppear:; that is, instead of printing the error only the first time the keyboard is shown and never again, the error is not printed the first time but every time after. This is causing a major headache for me.
Override -viewDidAppear:, not -viewWillAppear, and make sure to call [super viewDidAppear:]. You should not perform animations when you are not on screen ("will appear"). And the -viewDidAppear: docs explain that you must call super because they have their own things to do.
I was getting a similar error when quickly:
Dismissing a modal view
Updating the main view
Presenting a new modal view
I noticed I was only getting it in the simulator and not on the device. Additionally, I was getting caught in an infinite loop.
My solution was to delay the presenting of the new modal view. It seems that quickly updating the view hierarchy caused some sot of race condition in Apple's code.
With that in mind, try this:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.1];
}
You may be having issues presenting the keyboard for a UITextField that ins't yet on screen.
This may be causing problems similar to mine.
Also, you pause giving the hierarchy time to update before presenting the keyboard, just in case.
Hope this helps.
Check you are only interacting with the UI on the main thread. I got wait_fences: failed to receive reply: 10004003 while I was sitting there waiting for a UIAlertView to show for about 5 seconds because the relevant code was executed on a background thread. You can make sure by putting your code in block and sending it to the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
if (!success) {
// Inform user that import failed
UIAlertView * importFailedAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ErrorTitle5", #"Import failed")
message:NSLocalizedString(#"Error5", #"Something went wrong")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil];
[importFailedAlert show];
}
});
After trying everything I could find on Google and none of it working, this is what solved the problem for me. The key is that I'm doing this stuff in the willDismissWithButtonIndex delegate method. Before I was doing it elsewhere.
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
[myTextField resignFirstResponder];
[myTextField removeFromSuperview];
[myTextField release];
}
If you have the following line in viewDidLoad, it can cause this message. Comment the following line.
[[UIApplication sharedApplication] setStatusBarHidden:YES]; //This line should be commented
(You can disable the status bar from the application plist file instead).
After few tests the big rule is: "Do not perform animation before animated dismissal or animated show.".
For example:
do not call -dismissModalViewControllerAnimated:YES after the delegation callback of an UIAlertView -alertView:willDismissWithButtonIndex: (wait the fade out of the alert view before doing this using the -alertView:didDismissWithButtonIndex: callback)
do not try to show the keyboard (becomeFirstResponder) before your view controller is on screen.
Bad things may happen.
Hope it will be useful ;-)
This worked for me to get the keyboard to show itself immediately, without animation or delay.
Let textField be an instance variable of MyViewController (a subclass of UIViewController).
Call [textField becomeFirstResponder] in initWithNibName:bundle: (for a subclass of UIViewController) or initWithStyle: (for a subclass of UITableViewController), not in viewDidLoad. E.g.:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[textField becomeFirstResponder];
}
return self;
}
Or, call it just after initializing but before pushing the UIViewController. E.g.:
MyViewController *viewController = [[MyViewController alloc] init];
[viewController.textField becomeFirstResponder];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
You have done [textfield becomeFirstResponder];
And after you get the value from textfield in your code, do [textfield resignFirstResponder];. That will help you, I think.
If you're running the current iPhone Simulator 4.0, this error message appears frequently when rotating the screen (or when animating after rotating the screen) accompanied by 1-2 second lag in the animations.
It is a bug in this version of the Simulator and should be fixed soon.
See here for more info: http://www.iphonedevsdk.com/forum/iphone-sdk-development-advanced-discussion/17373-wait_fences-failed-receive-reply-10004003-a.html
Your problem is related.
override viewDidappear, not viewWillAppear:
-(void) viewDidAppear:(BOOL) animated
{
[super viewDidAppear:animated];
[myTextField becomeFirstResponder];
}
I can simulate this one-on-one by means of this UIAlertView code.
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"defineTitle",#"defineTitle")
message:NSLocalizedString(#"defineBody", #"defineBody")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Ok", #"Ok")
otherButtonTitles:nil];
[alert show];
When the NSLocalizedString are not defined in the Localizable.strings file it will take
to long to search for the texts, so the alert will show and the “wait_fences: failed to receive reply: 10004003” will be shown.
For me I only had to add the texts to the Localizable.strings files and my problems were solved. Maybe this is also the case for other occurances?
Also with the UIAlertView. What solved it for me was having the resign as below, as warehouselabs mentioned earlier.
- (void)didPresentAlertView:(UIAlertView *)alertView
{
[txtListingPassword becomeFirstResponder];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[txtListingPassword resignFirstResponder];
}
The other delegates of UIAlertViewDelegate did not fix the issue.
The problems is that there's a race condition in Apple's code. Usually, this has to something to do with incorrect UI updates.
In my experience, you either haven't called the super in viewDidAppear, viewWillAppear etc. Or you try to display a UIAlertView in viewDidLoad or viewWillAppear.
When you add a UIAlertView, the framework needs a reference to your parent view. But if you're in viewWillAppear or viewDidLoad, the view isn't actually displayed... You should consider move the code to viewDidAppear where the view is ready to be used by UIAlertView.
Is the Text Field contained within that view, or within something else? You can only send the 'becomeFirstRepsonder' to something that is contained directly within that view. If it's stored in some other widget component, you shouldn't set the first responder status in this widget, but rather in the widget that's being created. For example, if you're adding the text field to an alert view, because the show happens asynchronously, it might not be up by the time you call the becomeFirstResponder. (Ideally, you'd have your own alert view class and define the text field within that, and when that view receives the viewDidAppear, you'd set the textfield as first responder at that point.)
I also get the message wait_fences: failed to receive reply: 10004003 and my viewWill... and viewDid... methods do nothing but send messages to super. In my case it happens when I have a UIAlertView showing in my GameViewController and the user instead presses the iPhone round device button and then returns to the app. This looks out of my hands.
Alertview or actionsheets should be shown on main threads...so if your making any synchronous connections and performing that operation on another thread and showin alerts on the basis of output you received from that operation then you will get this error message wait_fences: failed to receive reply: 10004003 . You can do something like....
[self performSelectotOnMainThread:#selector(handleOutput:) withObject:output waitUntilDone:YES/NO];
and show alerts in handleOutput method passing the output response string as the parameter.
Solution is here!
I had same error, now I got the solution, this may help you.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
[self performSelector:#selector(YOUR_METHOD) withObject:nil afterDelay:0.1];
}