In xcode
timer = [NSTimer timerWithTimeInterval:auto_panic_upadte_secs
invocation:panicPendingTickInvocation repeats:FALSE];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
It gets past these lines of code, But as soon as I run it just SIGABRTs without/before my invocation happening.
Any idea to do this?
You may need to retain the arguments to your NSInvocation with the method
[panicPendingTickInvocation retainArguments];
To stop and autoreleased arguments from being released before you timer firers.
Related
This calls my selector repeatedly each 60 seconds as desired:
autoDeleteTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
This next line doesn't call it at all. Not initially nor after 60 seconds:
autoDeleteTimer = [[NSTimer alloc] initWithFireDate: [NSDate dateWithTimeIntervalSinceNow:1] interval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
Can anyone explain why? Thanks.
You need to add the second timer to the main loop:
[[NSRunLoop mainRunLoop] addTimer: autoDeleteTimer forMode:NSDefaultRunLoopMode];
From the documentation of the method:
- (id)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
Return Value:
The receiver, initialized such that, when added to a run loop, it will
fire at date and then, if repeats is YES, every seconds after that.
You must add the new timer to a run loop, using addTimer:forMode:.
Upon firing, the timer sends the message aSelector to target. (If the
timer is configured to repeat, there is no need to subsequently re-add
the timer to the run loop.)
NSTimer Apple Doc
I'm creating an NSTimer:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
However, the timer doesn't get fired. The method doesn't get invoked.
If I print my date I get the following:
2012-10-12 15:19:02.786 MyApp[1768:303] fire date: 2012-10-12 13:21:02 +0000
Shouldn't it be "2012-10-12 15:21:02" ? Somehow the hours are wrong. But why? If I change the Time Zone from UTC/GMT +1 hour (I'm sitting in Germany) to another, the date is still 2012-10-12 13:19:02 plus two seconds.
What am I doing wrong?
Thanks!
A time created with initWithFireDate must be added to a run loop, e.g.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Use scheduledTimerWithTimeInterval to create a timer that is automatically scheduled on the current run loop.
PS: The description method of NSDate uses always GMT, that probably explains your output.
addTimerIf you create your timer like this:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
You must add the timer in the RunLoop like this:
[[NSRunLoop currentRunLoop] addTimer:saveProgressSizeTimer forMode:NSDefaultRunLoopMode];
Here is how I am attempting to update my UIProgressView in my iOS app.
[self.progressView setProgress:3.0/10.0 animated:YES];
// check the value.
NSLog(#"Progress: %0.1f", self.progressView.progress);
Why is NSLog outputting 0.0? Shouldn't it output 0.3? The progress bar isn't changing either.
First of all, make sure you set the progress value on the main thread. (and that self.progressView does in fact refer to your UIProgressView)
If that doesn't help, you may want to explicitly give the runloop some time to catch up on UI changes, e.g. using:
NSDate* futureDate = [NSDate dateWithTimeInterval:0.001 sinceDate:[NSDate date]];
[[NSRunLoop currentRunLoop] runUntilDate:futureDate];
However, you should be very careful using hacks like this, see:
Is calling -[NSRunLoop runUntilDate:] a good idea?
Using [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]] to let the scheduled selectors fire
NSRunloops and forcing event processing
So I'm starting a new NSThread that I want to be able to use later by calling performSelector:onThread:.... From how I understand it calling that methods add that call to the runloop on that thread, so on its next iteration it will pop all these calls and subsequently call them until there is nothing left to call. So I need this kind of functionality, an idle thread ready for work that I just can call upon it. My current code looks like this:
- (void)doInitialize
{
mThread = [[NSThread alloc] initWithTarget:self selector:#selector(runThread) object:nil];
[mthread start];
}
- (void)runThread
{
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
// From what I understand from the Google machine is that this call should start the
// runloop on this thread, but it DOESN'T. The thread dies and is un-callable
[[NSRunLoop currentRunLoop] run];
[pool drain];
}
- (void)scheduleSomethingOnThread
{
[self performSelector:#selector(hardWork) onThread:mThread withObject:nil waitUntilDone:NO];
}
But the thread is not kept alive, and the performSelector:onThread does not do anything. How do I go about this the right way?
A run loop requires at least one "input source" to run. The main run loop does, but you have to add a source manually to get a secondary run loop's -run method to do anything. There's some documentation on this here.
One naïve way to get this to work would be just to put [[NSRunLoop currentRunLoop] run] in an infinite loop; when there's something to do, it'll do it, and return immediately otherwise. The problem is that the thread will take a decent amount of processor time simply waiting for something to occur.
Another solution is to install an NSTimer on this run loop to keep it alive.
But, if possible, you should use a mechanism designed for this sort of thing. If possible, you may want to use NSOperationQueue for background operations.
this piece of code should force the thread to wait forever
BOOL shouldKeepRunning = YES; // global
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; // adding some input source, that is required for runLoop to runing
while (shouldKeepRunning && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); // starting infinite loop which can be stopped by changing the shouldKeepRunning's value
It took me hours to figure out how to implement a timer into my program, but when it runs, the app doesn't load completely as it did before the timer.
In my main.m:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
OutLauncher *theLauncher = [[OutLauncher alloc] init];
NSTimer *theTimer = [theLauncher getTimer];
[theTimer retain];
[[NSRunLoop currentRunLoop] addTimer: theTimer forMode: NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
[pool release];
return 0;
}
The file OutLauncher is being imported into that, which looks like this:
- (void)doStuff {
NSLog( #"Doing Stuff");
}
- (NSTimer *)getTimer{
NSTimer *theTimer;
theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: #selector(doStuff) userInfo:nil repeats:YES];
return [theTimer autorelease];
}
The timer works, the console updates every second with the phrase "doing stuff" but the rest of the program just won't load. It will if I comment out the code I added to int main though
A few things:
You don't need to autorelease the timer you return after setting one up with [NSTimer scheduledTimerWithTimeInterval:] It is already autoreleased.
The timer created via scheduledTimerWithInterval is already added to the default run loop. So you don't need to use the following:
[[NSRunLoop currentRunLoop] addTimer: theTimer forMode: NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
In fact, you don't even need to keep a reference to the timer unless you need to cancel it yourself.
Here is what apple has to say about what you are doing in the documentation
run
Puts the receiver into a permanent
loop, during which time it processes
data from all attached input sources.
(void)run Discussion If no input sources or timers are attached to the
run loop, this method exits
immediately; otherwise, it runs the
receiver in the NSDefaultRunLoopMode
by repeatedly invoking
runMode:beforeDate:. In other words,
this method effectively begins an
infinite loop that processes data from
the run loop’s input sources and
timers.
Manually removing all known input
sources and timers from the run loop
is not a guarantee that the run loop
will exit. Mac OS X can install and
remove additional input sources as
needed to process requests targeted at
the receiver’s thread. Those sources
could therefore prevent the run loop
from exiting.
If you want the run loop to terminate,
you shouldn't use this method.
Instead, use one of the other run
methods and also check other arbitrary
conditions of your own, in a loop. A
simple example would be:
BOOL shouldKeepRunning = YES;
// global NSRunLoop *theRL =
[NSRunLoop currentRunLoop]; while
(shouldKeepRunning && [theRL
runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]]);
where shouldKeepRunning is set to NO
somewhere else in the program.
Availability Available in iOS 2.0 and
later.
So it looks like your code is doing what it is supposed to do. It is Logging all the timer events and waiting indefinitely for the run loop.
It looks like you're making it a lot more complicated than it needs to be. You don't need to put any code in your main.m file. If you want to fire the doStuff method every second, this is all the code you need:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: #selector(doStuff) userInfo:nil repeats:YES];
You don't need to (auto)release it yourself. timer is already autoreleased. If you want to be able to cancel the timer, you will need to keep a reference of it. Then when you want to cancel, you just call invalidate and set the reference to nil.