how to allocate NSTimer property from another class in my class - objective-c

I have two class. I have one property NSTimer in my first class like this:
#interface KKProgressTimer : UIView
#property(nonatomic,retain) NSTimer *TimeCount;
#end
I could create two object from KKProgressTimer class and add in my second class.
in my second class I want to allocate NSTimer property to every object KKProgressTimer class.but I can't please guide me!!!
//this loop check and get two object KKProgressTimer class
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[KKProgressTimer class]]) {
KKProgressTimer *Progress = (KKProgressTimer*)subview;
//now I want to allocate NSTimer property this here and define scheduledTimerWithTimeInterval for it
//timing = [[NSTimer alloc]init];
//timing = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(CountDown:) userInfo:timing repeats:YES];
}
}

I would probably create a method inside KKProgressTimer to start up its own timer and handle its own callbacks but if you want to do it from outside, try:
Progress.TimeCount = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(CountDown:) userInfo:timing repeats:YES];
Note, however that this means the object that contains the loop is going to get all the timer callbacks for both subviews.

My friend maybe you forget set method for TimeCount.
write this code in second class:
Progress.TimeCount = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(CountDown:) userInfo:timing repeats:YES];
and write this code in .m file KKProgressTimer class
- (void)setTimeCount:(NSTimer *)TimeCount {
if (TimeCount) {
TimeCount = nil;
}
}

Related

NSTimer Not Stopping When Invalidated

I have the following code in my .h file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <AVFoundation/AVFoundation.h>
#import <MapKit/MapKit.h>
#interface LandingController : UIViewController<CLLocationManagerDelegate> {
CLLocationManager *LocationManager;
AVAudioPlayer *audioPlayer;
}
#property (nonatomic, retain) NSTimer *messageTimer;
- (IBAction)LoginButton:(id)sender;
#end
I have the following code in my .m file:
#interface LandingController ()
#end
#implementation LandingController
#synthesize messageTimer;
- (void)checkForMessages
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"BINGO:"
message:#"Bingo This Works"
delegate:nil
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[alert show];
}
- (IBAction)LoginButton:(id)sender {
if ([UserType isEqualToString:#"Owner"]) {
if (messageTimer){
[self.messageTimer invalidate];
self.messageTimer = nil;
}
} else {
if (!messageTimer){
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
}
}
}
#end
But my timer doesn't want to stop when I call the invalidate.
The LoginButton is only pressed twice, once when the strResult is = to "Guard" and then the application changes it to be equal to "Owner" and the user presses the login button again, so I don't think I'm setting multiple timers.
After pressing the login button and starting the timer I segue to another view and then segue back to press the login button once more which is when I want the timer to stop. Do I need to do anything special to get the messageTimer since I switched views for a moment and then came back?
Any ideas?
Thanks!
You need to call [self.messageTimer invalidate] on the same thread on which you created the timer. Just make sure that the timer is created and invalidated on main thread.
dispatch_async(dispatch_get_main_queue(), ^{
if ([UserType isEqualToString:#"Owner"]) {
[self.messageTimer invalidate];
self.messageTimer = nil;
} else {
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
}
});
NSTimer is retained by NSRunLoop, so the only way I see your issue happening is if you're actually creating more than one timer and invalidating only what you have reference to.
Example:
if(!timer)
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:(self) selector:#selector(processTimer) userInfo:nil repeats:YES];
Have you try to put repeat as No
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:NO];
If the code at the end (starting with if) is called twice with UserType != Owner, you create a new timer without invalidating the old one. Now two timers are running. If the code executes a third time, you will add a third timer and so on. Executing the code with UserType == Owner only invalidates the last timer and even it is called repeatly, it does not invalidate older timers.
You have a timer leak. ;-)
How about put an NSLog in your checkForMessages method? It would be easier to check if there's really only 1 timer.
(I'd rather put this in a comment, but I don't have that much reputation....)
I have an approach for stopping or deactivate the timer, Before apply this make sure that you tried all the cases as mentioned above so you can also understand that why this approach used at last.
// Instead of self use NSTimer class, it will not provide you any crash and in selector placed any empty function and setRepeats to NO
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:100.0
target:NSTimer selector:#selector(emptyFunctionCalling)
userInfo:nil
repeats:NO];
[self.messageTimer invalidate];
self.messageTimer = nil;
So whenever the case occured that timer will not stopping then entering in this code the timer will stops permanently.
Its weird but invalidating passed timer reference and created timer reference worked for me.
delayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateDelayLable:) userInfo:nil repeats:YES];
-(void)updateSendDataDelayLable:(NSTimer*)timer{
delayValueForGNSS--;
if (delayValueForGNSSSend==0) {
[timer invalidate];
timer = nil;
[delayTimer invalidate];
delayTimer = nil;
}
}

Start & Stop Timer

I have a timer that calls a function every 10 seconds:
[NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
It calls the function:
- (void)checkForMessages
{
//do something here
}
Two questions:
How do I stop the timer if needed?
Can I put this timer and function somewhere so that I can call it from different view controllers?
"scheduledTimerWithTimeInterval" returns an "NSTimer" object.
If you hold onto that object (e.g. set and get it via a "property"), you can stop it via the NSTimer invalidate method.
And since you're asking for code, add this to your view controller's .h #interface:
#property (strong) NSTimer * messageTimer;
Then, in your view controller's .m file:
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
Makes sense?

NSTimer causes "unrecognized selector" crash when it fires

I'm using a NSTimer to run an animation (for now just call it myMethod). However, its causing a crash.
Here's the code:
#implementation SecondViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void) myMethod
{
NSLog(#"Mark Timer Fire");
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"We've loaded scan");
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(myMethod:)
userInfo:nil
repeats:YES];
animationTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(myMethod:) userInfo:nil repeats: YES];
}
And here's the output during the crash
-[SecondViewController myMethod:]: unrecognized selector sent to instance 0x4b2ca40
2012-06-21 12:19:53.297 Lie Detector[38912:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SecondViewController myMethod:]: unrecognized selector sent to instance 0x4b2ca40'
So what am I doing wrong here?
I ran into this problem while using Swift. It may not be evident that in Swift I discovered that the target object of NSTimer must be an NSObject.
class Timer : NSObject {
init () { super.init() }
func schedule() {
NSTimer.scheduledTimerWithTimeInterval(2.0,
target: self,
selector: "myMethod",
userInfo: nil,
repeats: true)
}
func myMethod() {
...
}
}
Hope this helps somebody.
either you can use only
- (void)myMethod: (id)sender
{
// Do things
}
or you can do (remove : from both the method name)..
animationTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(myMethod) userInfo:nil repeats: YES];
hope this will help you
replace this
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(myMethod:)
userInfo:nil
repeats:YES];
by this
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(myMethod)
userInfo:nil
repeats:YES];
The timer's action method should take one argument:
- (void)myMethod: (NSTimer *)tim
{
// Do things
}
The name of this method is myMethod:, including the colon. Your current method's name is myMethod, without the colon, but you create your timer by passing a method name that has it: selector:#selector(myMethod:).
Currently, then, the timer sends the message myMethod: to your object; your object doesn't respond to that (but would respond to myMethod) and raises an exception.

NSTimer within a class

I have a timer class set up that is basically handling all of count down timer logic. All it does is on button press - counts from 60 to 0 seconds.
I have the following code in a Timer.m class.
- (void)advanceTimer
{
self.lengthOfTime = [NSNumber numberWithInt:self.lengthOfTime.intValue - 1];
NSLog(#"%#",self.lengthOfTime);
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(advanceTimer) userInfo:nil repeats:NO];
}
- (void)startCountdown
{
if (!self.lengthOfTime) self.lengthOfTime = [NSNumber numberWithInt:60];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(advanceTimer) userInfo:nil repeats:NO];
}
What I am looking to do is create a timer object in my View Controller that will update a label from the ViewController.m. Currently - the class works because I can NSLog from the Timer class and it counts down correctly. I thought about having the advanceTimer method return - but I can't seem to wrap my head around how to update the label in the ViewController with the returned data.
The only way I cold get the return to work was to have a button that refreshed the label to the correct countdown time... I can't get it to automatically count down...
Well, if you know how to update a label by clicking a button, you have everything in place to connect everything else:
If your view controller has an IBOutlet for the label and an IBAction that updates it, why not call the view-controller's action in your advanceTimer method?
Yet easier, you could connect your timer class to the label.
You might do it like this:
// Timer.h:
#interface Timer : NSObject
#property (retain, nonatomic) IBOutlet UILabel *timeLabel;
#property (assign, nonatomic) NSInteger secondsRemaining;
#property (assign, nonatomic) NSTimer *timer;
- (IBAction)startCountdown:(id)sender;
- (IBAction)stopCountdown:(id)sender;
- (void)timerFired:(NSTimer *)timer;
#end
// Timer.m
#implementation Timer
#synthesize timeLabel = timeLabel_;
#synthesize secondsRemaining = secondsRemaining;
#synthesize timer = timer_;
- (void)setTimer:(NSTimer *)timer
{
if (timer = timer_)
return;
[timer_ invalidate];
timer_ = timer;
}
- (void)scheduleTimer
{
if (self.secondsRemaining <= 0) {
self.timer = nil;
} else {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired:) userInfo:nil repeats:NO];
}
}
- (void)timerFired:(NSTimer *)timer
{
self.secondsRemaining -= 1;
NSString *displayString = [NSString stringWithFormat:#"%d", self.secondsRemaining];
self.timeLabel.text = displayString;
[self scheduleTimer];
}
- (IBAction)startCountdown:(id)sender
{
self.secondsRemaining = 60;
[self scheduleTimer];
}
- (IBAction)stopCountdown:(id)sender
{
self.timer = nil;
}
- (void)dealloc
{
[timeLabel_ release];
[super dealloc];
}
#end
This code has a two benefits:
You can cancel your timer.
Your view controller does not need to know anything about this — you can set this up in interface builder, entirely.
Correct me if I'm wrong, but I think you should retain that NSTimer in a class member. Otherwise the timer is destroyed when finishing the method.
#property (nonatomic,retain) NSTimer * yourTimer;
In the .m file
#synthesize yourTimer;
And then
- (void)advanceTimer
{
self.lengthOfTime = [NSNumber numberWithInt:self.lengthOfTime.intValue - 1];
NSLog(#"%#",self.lengthOfTime);
self.yourTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(advanceTimer) userInfo:nil repeats:NO];
}
- (void)startCountdown
{
if (!self.lengthOfTime) self.lengthOfTime = [NSNumber numberWithInt:60];
self.yourTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(advanceTimer) userInfo:nil repeats:NO];
}
I fixed also your NSNumber alloc, so there are no memory leaks ;)
Explaining it, NSTimer scheduledTimerWithTimeInterval: gives you an NSTimer with autorelease. If this Timer is not retained by some member, it gets released as soon as the method ends and, since no other pointer is retaining it, it gets freed. Maybe that's the explanation ;). Never worked with NSTimers
The countdown class needs to save a link back to the ViewController and then call a method on it.
One approach would be to use the delegate pattern. Have the Countdown class's init method as initWithDelegate:(id)delegate and a predefined callback method (like updateCountdown:(NSNumber*)currentCountdown). The ViewController sends itself as the delegate and implements the update method.
Another approach is the target/action pattern. NSTimer uses this approach. The init method would be initWithTarget:(id)target selector:(SEL)selector. The ViewController sends itself as the target and whatever selector it wants to use (as long as it takes an NSNumber as it's sole argument).
In both cases in advanceTimer the Countdown class will use performSelector:withObject: to call the ViewController's update method.
If you really want a true one second timer then set it to repeat. Otherwise you will drift slowly by the amount of time the advanceTimer method takes to fire and complete. At the end of the countdown use a reference to the timer to invalidate it.

NSTimer doesn't call method

I'm really frustrated now, googled the whole internet, stumbled through SO and still didn't find a solution.
I'm trying to implement an NSTimer, but the method which I defined doesn't get called. (seconds are set correctly, checked it with breakpoints). Here is the code:
- (void) setTimerForAlarm:(Alarm *)alarm {
NSTimeInterval seconds = [[alarm alarmDate] timeIntervalSinceNow];
theTimer = [NSTimer timerWithTimeInterval:seconds
target:self
selector:#selector(showAlarm:)
userInfo:alarm repeats:NO];
}
- (void) showAlarm:(Alarm *)alarm {
NSLog(#"Alarm: %#", [alarm alarmText]);
}
The object "theTimer" is deined with #property:
#interface FooAppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> {
#private
NSTimer *theTimer;
}
#property (nonatomic, retain) NSTimer *theTimer;
- (void) setTimerForAlarm:(Alarm *)alarm;
- (void) showAlarm:(Alarm *)alarm;
What am I doing wrong?
timerWithTimeInterval simply creates a timer, but doesn't add it to any run loops for execution. Try
self.theTimer = [NSTimer scheduledTimerWithTimeInterval:seconds
target:self
selector:#selector(showAlarm:)
userInfo:alarm repeats:NO];
instead.
Also don't forget to check if
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats
is called in the main thread.
You've created an NSTimer object but you haven't scheduled it to be run. timerWithTimeInterval:target:selector:userInfo:repeats: creates a timer that you can schedule to run later, for example, to create a timer at application launch and have it start counting when the user presses a button. Either call
[[NSRunLoop currentRunLoop] addTimer:theTimer forMode:NSDefaultRunLoopMode]
at the end of setTimerForAlarm or replace
theTimer = [NSTimer timerWithTimeInterval:seconds
target:self
selector:#selector(showAlarm:)
userInfo:alarm repeats:NO];
with
theTimer = [NSTimer scheduledTimerWithTimeInterval:seconds
target:self
selector:#selector(showAlarm:)
userInfo:alarm repeats:NO];
which creates a timer and immediately schedules it.
Well you may want to actually schedule your NSTimer on the run loop :) instead of timerWithTimeInterval use scheduledTimerWithTimeInterval.
theTimer = [NSTimer scheduledTimerWithTimeInterval:seconds
target:self
selector:#selector(showAlarm:)
userInfo:alarm repeats:NO];
While all of the answers are right, there is an even simpler solution that doesn't involve a NSTimer at all. Your setTimerForAlarm: implementation can be reduced to one simple line:
[self performSelector:#selector(showAlarm:) withObject:alarm afterDelay:[[alarm alarmDate] timeIntervalSinceNow]]