What is the proper way to disable NSTimer? - ios4

I am writing an app where the main view controller has several NSTimers that control different events. This works well except for a few oddball cases where the timers don't seem to get disabled when I pop this main view controller off my navigation stack.
My question is this: what is the proper way to invalidate or disable an NSTimer so that it doesn't get called again?
Right now, I instantiate an NSTimer like this:
alertViewTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(alertTimer) userInfo:nil repeats:YES];
And I use this macro to invalidate the NSTimer:
#define TimerInvalidateAndNil(A) \
if(A != nil) \
{\
if([A isValid])\
{\
[A invalidate]; \
}\
A = nil; \
}

Related

iOS 7 MFMailComposeViewController status bar color

Converting a legacy app for iOS 7. Have most of the problems covered, but we have a feature that emails an error log using MFMailComposeViewController, and the status bar is coming up black on black in that view.
The status bar text color is set to white globally using plist settings, and that seems to handle everything else just fine. Only the email VC is acting up. (We present it using presentModalViewController.)
Has anyone figured out how to crack this nut?
Update: Tried subclassing MFMailComposeViewController and implementing preferredStatusBarStyle, but it's not invoked, even after setting "View controller-based status bar" to YES in the plist.
The following kluge appears to do the job:
// Present the email controller. The delegate will dismiss it.
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion < 7.0f) {
[viewController presentViewController:emailController animated:YES completion:^{}];
}
else {
// Need a song and dance to get the header bar to show correctly. (And presentModalViewController is deprecated anyway.) Note that this code doesn't actually change the email controller's header, but it somehow lets the header below "show through" when it wouldn't otherwise. (I know -- like many of the iOS 7 fixes this makes no sense. But it works. (So far.))
#warning Sometimes produces console message "Presenting view controllers on detached view controllers is discouraged <XxxxViewController: 0xc658a70>"
[viewController presentViewController:emailController animated:YES completion:^{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
&& [[UIApplication sharedApplication] respondsToSelector:NSSelectorFromString(#"setStatusBarStyle:")]) {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
#endif
}];
}
#else
[viewController presentModalViewController:emailController animated:YES];
#endif

Handle touch event in uiimage in uiwebview

I am drawing one image (called image1) on top of the another image (called main image) And saved that image locally. Now I am loading the "main image" in the UIWebview. It is fine. But now I need to handle event when touch on the "image1".
Please help me.
Thanks,
Jasmine.
Try this
EDITED
create a UIWebView object 'webview' and create a UITapGestureRecognizer object 'TapGesture'
then
TapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapAction:)];
TapGesture.numberOfTapsRequired = 1;
TapGesture.delegate = self;
[self.webview TapGesture];
In this case once you click the image it will call 'tapAction ' method ,In that you can add your code
in TapAction you can add
[UIView animateWithDuration:1.0 animations:^
{
// you can add zooming frame here
}
completion:^(BOOL finished)
{
[self performTransition:UIViewAnimationOptionTransitionCrossDissolve];
}
];

NSTimer in NSOperation subclass

Dear community.
I try to setup NSTimer:
#interface GetExternalInfo : NSOperation {
NSTimer *keepAliveTimerMain;
#property (nonatomic,retain) NSTimer *keepAliveTimerMain;
.m:
#synthesize keepAliveTimerMain
-(void) main;
{
self.keepAliveTimerMain = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(keepAlive:) userInfo:nil repeats:YES];
[keepAliveTimerMain fire];
[[NSRunLoop currentRunLoop] addTimer:self.keepAliveTimerMain forMode: NSDefaultRunLoopMode];
BOOL timerState = [keepAliveTimerMain isValid];
NSLog(#"STAT:Timer Validity is: %#", timerState?#"YES":#"NO");
- (void)keepAlive:(NSTimer *)theTimer
{
BOOL currentState = [self isCancelled];
NSLog(#"STAT:cancelled state is %#.\n",currentState?#"YES":#"NO");
}
In Logs
2011-02-02 18:58:31.041
snow[54705:5d07] STAT:cancelled state
is NO. 2011-02-02 18:58:31.042
snow[54705:5d07] STAT:Timer Validity
is: YES
i see this only once. No next repeat attempts every 5 seconds
any opinions in this case? GC is enabled.
Do you have a runloop in the current thread? The timer needs a runloop to be able to fire. I notice you call -fire manually which explains why -keepAlive is called, but this doesn't actually start the timer.
You need to add your timer to a run loop, something like [[NSRunLoop currentRunLoop] addTimer:keepAliveTimerMain forMode: NSDefaultRunLoopMode];.
EDIT: The code you posted shows that you manually fire the timer before adding it to the runloop. This will fire and invalidate the timer, so you are actually trying to schedule an invalid timer on the runloop. That is why you only see the NSLog message once.

Action Trigger when I hold UIButton for 2 second in iPhone

I have a UIButton in my application and an action which is triggered when I TouchDown UIButton.
Is it possible to detect a Touch-and-Hold on the UIButton on the iPhone? I want my action to trigger when the user holds the button for 2 seconds or more.
Any Ideas?
UILongPressGestureRecognizer is what you need. For example,
UILongPressGestureRecognizer *longPress_gr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(doAction:)];
[longPress_gr setMinimumPressDuration:2]; // triggers the action after 2 seconds of press
[yourButton addGestureRecognizer:longPress_gr];
To let your action get triggered only once(ie., when the 2 seconds duration is over), make sure you have your doAction: method looks something like this,
- (void)doAction:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
// Your code here
}
}
On the other way you can use this NBTouchAndHoldButton. This is exactly what you want, and it is very easy to implement it:
TouchAndHoldButton * pageDownButton = [TouchAndHoldButton buttonWithType:UIButtonTypeCustom];
[pageDownButton addTarget:self action:#selector(pageDownAction:) forTouchAndHoldControlEventWithTimeInterval:0.2];
Good luck!

CLLocation manager updates from background thread

I'm launching a localization request using Grand Central Dispatch :
- (void) findGroceriesNearMe {
dispatch_queue_t downloadQueue = dispatch_queue_create("Groceries downloader", NULL);
dispatch_async(downloadQueue, ^{
CLLocationCoordinate2D userLocation = [LocationManagerController findMeWithCaller:self];
dispatch_async(dispatch_get_main_queue(), ^{
[self userSuccessFullyFound:userLocation];
});
});
dispatch_release(downloadQueue);
}
It calls a static method in my Singleton class LocationManager Controller :
+ (CLLocationCoordinate2D) findMeWithCaller: (UIViewController *) viewController {
LocationManagerController *locationManagerController = [LocationManagerController locationManagerController];
[locationManagerController startUpdates];
while(![locationManagerController getterDone]){
//mystique pour nous-- a approfondir
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
In the startUpdates method, the CLLocationManager, property of LocationManagerController, is initialized and asked to startUpdatingLocation.
Finally, the method when location updates happen :
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
locationDenied = NO;
NSLog(#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude);
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
// On vérifie que la newLocation est récente
if (abs(howRecent) > 10.0) {
return;
}
// Test if it's not an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// Test the measurement to see if it meets the desired accuracy
if (newLocation.horizontalAccuracy <= manager.desiredAccuracy)
{
latitude = newLocation.coordinate.latitude;
longitude = newLocation.coordinate.longitude;
locationDefined = YES;
[self setterDone:YES];
}
}
My problem is that the locationManager only send 3 location updates and then stops sending updates even though I didn't ask it to stop. So basically, I never get out of the while(![locationManagerController getterDone]) loop.
By the way, before trying to implement this using GCD, it was working fine so I guess the issue has to do with my implementation of multi-threading.
Any idea ?
Edit
I don't get any error in the console. The program just keeps running but I'm stuck in that while loop and nothing else happens after the 3 first location updates.
Thanks !
From CLLocationManager class reference:
Configuration of your location manager object must always occur on a
thread with an active run loop, such as your application’s main
thread.
A guess. If you are sitting at your desk and testing with your simulator the accuracy may not get better what you want
if (newLocation.horizontalAccuracy <= manager.desiredAccuracy)
So you may get stuck in your loop. Try with higher accuracy while at your desk. Also consider if the accuracy is never better that what you want since it maybe that the gps reception is not good.
Let me know if that helps or if I was way off the mark :-)
-- Fasttouch

Resources