Running NSTimer on a thread - iphone

I am trying to run a NSTimer on a thread using iPhone SDK 3.0. I think I am doing everything correctly (new runloop etc.). If I call [timer invalidate] on viewDidDissappear though I get this error:
bool _WebTryThreadLock(bool), 0x3986d60: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Program received signal: “EXC_BAD_ACCESS”.
Here is my code:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[activityIndicator startAnimating];
NSThread* timerThread = [[NSThread alloc] initWithTarget:self selector:#selector(timerStart) object:nil]; //Create a new thread
[timerThread start]; //start the thread
}
-(void)timerStart
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
//Fire timer every second to updated countdown and date/time
timer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(method) userInfo:nil repeats:YES] retain];
[runLoop run];
[pool release];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[timer invalidate];
}
When I remove the line invalidating the timer everything works fine. Am I not supposed to invalidate it or am I making some other mistake?
Thanks

Try
[timer performSelector:#selector(invalidate) onThread:timerThread withObject:nil waitUntilDone:NO];
instead. You will have to make timerThread an ivar of your view controller.

- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSThread* timerThread = [[NSThread alloc] initWithTarget:self selector:#selector(timerStart) userInfo:nil repeats:TRUE];
[timerThread start];
}
-(void)timerStart
{
#autoreleasePool{
NSRunLoop *TimerRunLoop = [NSRunLoop currentRunLoop];
[NSTimer scheduleTimerWithInterval:0.1 target:self selector:#selector(methodName:) userInfo:nil repeat:YES];
[TimerRunLoop run];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}

I guess you have done some UI work in "method".
timer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(method) userInfo:nil repeats:YES] retain];
From the log, it seems you have done UI updating work it in "Timer" thread in "method".
you can use block to dispatch work on main thread or performSeletorOnMainThread for doing "method"

Related

How to run another thread and using that thread run timer to repeat process?

Hi i want to start a timer with another thread and want to repeat process in that thread. i had tried but it doesn't work.
my code snippet is given below
[NSThread detachNewThreadSelector:#selector(setupTimerThread) toTarget:self withObject:nil];
-(void)setupTimerThread
{
NSLog(#"inside setup timer thread");
// self.startTiemr = [[NSTimer alloc]init];
startTiemr = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(triggerTimer) userInfo:nil repeats:YES];
runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:startTiemr forMode:NSRunLoopCommonModes];
[runLoop run];
}
can anyone suggest me a proper way to do that?
Thanks in advance.
#import "TimePassViewController.h"
#interface TimePassViewController ()
#end
#implementation TimePassViewController
{
NSTimer *timer;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// [self performSelectorOnMainThread:#selector(yourmethod) withObject:nil waitUntilDone:NO];
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:#selector(yourmethod)
object:nil];
[myThread start]; // Actually create the thread
}
-(void)yourmethod
{
#autoreleasepool
{
NSRunLoop *TimerRunLoop = [NSRunLoop currentRunLoop];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerMethod) userInfo:nil repeats:YES];
[TimerRunLoop run];
}
//timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerMethod) userInfo:nil repeats:YES];
}
-(void)timerMethod
{
NSLog(#"aaaaaaaaaaaa");
//[timer invalidate];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
try this code:
NStimer *uptimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(bachground_todaylist) userInfo:nil repeats:YES];
-(void)bachground_todaylist
{
[self performSelectorInBackground:#selector(yourmethod) withObject:nil];
}
you wants to stop proces
[uptimer invalidate];

Stop NSTimer running from application didFinishLaunchingWithOptions

I have start a timer to call a method after 10 seconds. the timer start from didFinishLaunchingWithOptions. it works fine but I want to stop that timer from another UISubclass at the time of logout. How I can do this my code is
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSThread sleepForTimeInterval:2.0];
[self.window addSubview:viewController.view];
[self setupTimer];
[self.window makeKeyAndVisible];
return YES;
}
-(void)setupTimer;
{
timer = [NSTimer timerWithTimeInterval:10
target:self
selector:#selector(triggerTimer:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void)triggerTimer:(NSTimer*)timer;
{
NSLog(#"===============this method is call after every 10 second===========================");
Getlocation *object=[[Getlocation alloc] init];
[object updatelocation];
}
-(void)stopTimer:(NSTimer*)timer;
{
[timer invalidate];
timer=nil;
}
if([timer isValid])
[timer invalidate];
timer = nil;
Take an object of NSTimer.
Write this line where do you want to call method
timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(NEWTIMER) userInfo:nil repeats:YES];
Write this code there do you want stop timer.
[timer invalidate];
timer = nil;
[timer release];
if you want stop timer when your app came background .you should write this code into this method.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[timer invalidate];
timer = nil;
[timer release];
}
Write code in logout ButtonAction method.
-(IBAction)LogOutButtonPressed:(id)sender {
[timer invalidate]; timer = nil; [timer release];
}

How to invalidate timer after certain condition gets satisfied in the same method?

Hi i'm trying to show a custom progress bar in my iPhone app for that i'm writing a method to increment the progress bar value and once it's value becomes 100% then i need to invalidate my timer and i need to stop this recursion and show next viewController.
My code snippet is something like below,
-(void)progressNextValue
{
progressValue += 1.0f;
if(progressValue >= progress.maxValue){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"end" message:#"TimeOut!!!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
NSLog(#"Time Out!!!!");
[mytimer invalidate];
Second *sec = [[Second alloc] initWithNibName:#"Second" bundle:nil];
[self.view addSubview:sec.view];
}
progress.currentValue = progressValue;
mytimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(progressNextValue) userInfo:nil repeats:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
progress.maxValue = 100.0f;
[self progressNextValue];
}
Here even if my progressValue = progress.maxValue, mytimer is not getting invalidated.
Any help is appreciated in advance.
You are setting your timer each time the method is run regardless. Add a return statement, or place the timer instantiation in an else statement.
For example:
-(void)progressNextValue
{
progressValue += 1.0f;
if(progressValue >= progress.maxValue){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"end" message:#"TimeOut!!!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
NSLog(#"Time Out!!!!");
[mytimer invalidate];
Second *sec = [[Second alloc] initWithNibName:#"Second" bundle:nil];
[self.view addSubview:sec.view];
} else {
// Move this line inside the else statements so that it only gets run if
// the progress bar is not full.
mytimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(progressNextValue) userInfo:nil repeats:YES];
}
progress.currentValue = progressValue;
}
This code causes the issue,
mytimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(progressNextValue) userInfo:nil repeats:YES];
Here each time you are creating a timer with repeat, that's the issue.
Call the progressNextValue method from any other method:
-(void)tempMethod
mytimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(progressNextValue) userInfo:nil repeats:YES];
}
or just call it from:
- (void)viewDidLoad
{
[super viewDidLoad];
progress.maxValue = 100.0f;
mytimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(progressNextValue) userInfo:nil repeats:YES];
}
In order to invalidate your timer you need to call [myTimer invalidate]. Which you do. But myTimer in your case is not retained as far as I can see. So retain it when your alloc it and release it when you invalidate it.
Hope this helps.
Cheers!
Instead of calling your timer inside of progressNextValue, call it in viewDidLoad (or somewhere else that you want to start it). Keep a reference to your timer (so at the top of your page put NSTimer *t) and then when your conditions have been met do [t invalidate];
The problem is that when you call your timer inside of 'progressNextValue' you're telling it to repeat, so invalidating the timer there doesn't do much (because you have multiple timers going).

Timer doesn't start in viewWillAppear Methods

I want to start a timer when a viewWillAppear method gets called.
It's working perfectly, but I'm having a problem when I push a new view on this Current View, which already has a timer. When I pop that new View and recall viewWillAppear I want to start the timer again as before. I have most of the techniques but can't find a solution.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[NSThread detachNewThreadSelector:#selector(createTimer) toTarget:self withObject:self];
}
- (void)createTimer
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
gameTimer = [[NSTimer timerWithTimeInterval:1.00 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
timeCount = 360;
[runLoop run];
[pool release];
}
- (void)timerFired:(NSTimer *)timer
{
if(timeCount == 0)
{
[self timerExpired];
} else {
timeCount--;
if(timeCount == 0) {
[timer invalidate];
[self timerExpired];
}
}
timeLabel.text = [NSString stringWithFormat:#"%02d:%02d",timeCount/60, timeCount % 60];
}
- (void) timerExpired
{
//NSLog(#"Final == %#",arrayAnswers);
//NSLog(#"Attempt == %d",[arrayAnswers count]);
[gameTimer invalidate];
gameTimer = nil;
}
Well, based on experience, your problem is the timer's thread. Basically, the problem is here:
[NSThread detachNewThreadSelector:#selector(createTimer) toTarget:self withObject:self];
I'm not absolutely sure but I believe that your code is not really wrong. I haven't figured it out yet but I guess the NSTimer object is not being activated when detachNewThreadSelector: is used. Try executing the timer on the main thread.
[self performSelectorOnMainThread:#selector(createTimer) withObject:nil waitUntilDone:NO]
I've done this and got the results that I wanted.

Iphone facebook connect example does't call login screen. Why?

i added [self fbButtonClick:nil]; , but it does't call login screen. Why?
- (void)viewDidLoad {
_facebook = [[Facebook alloc] initWithAppId:kAppId];
[self.label setText:#"Please log in"];
_getUserInfoButton.hidden = YES;
_getPublicInfoButton.hidden = YES;
_publishButton.hidden = YES;
_uploadPhotoButton.hidden = YES;
_fbButton.isLoggedIn = NO;
[_fbButton updateImage];
[self fbButtonClick:nil];
}
You're suppose to call the authorize method on the _facebook object to login. That will call the login screen
i solved this problem with timer
NSTimer *timer = [[NSTimer timerWithTimeInterval:0.001
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:NO] retain];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- (void)timerFired:(NSTimer *)timer
{
[timer invalidate];
[timer release];
timer = nil;
[self fbButtonClick:nil];
}