NSTimer causes "unrecognized selector" crash when it fires - objective-c

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.

Related

How do I set a NSTimer to stop if a certain action is running?

I have a popup in a custom view controller that is presented after 1 minute thanks to my NSTimer.
My NSTimer code:
[NSTimer scheduledTimerWithTimeInterval:60.0f
target:self selector:#selector(methodB:) userInfo:nil repeats:YES];`
The method that reveals the popup
- (void) methodB:(NSTimer *)timer
{
//Do calculations.
[self showPopupWithStyle:CNPPopupStyleFullscreen];
}
I'm trying to set the NSTimer to stop running if the [self showPopupWithStyle:CNPPopupStyleFullscreen]; is currently open, running or active.
Then I would like to start the NSTimer back up again if the popup view controller is NOT open, running or active.
Any help, samples or examples would be greatly appreciated!
My project is written in Objective-C.
EDIT:
I tried the answers in the suggested "possibly similar" answer and it doesn't seem to work for what I am doing. How do I stop NSTimer?
This seems to do the trick.
#property (nonatomic, strong) CNPPopupController *popupController;
- (void)_timerFired:(NSTimer *)timer;
#end
NSTimer *_timer;
- (void)viewDidLoad {
[super viewDidLoad];
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self
selector:#selector(_timerFired:)
userInfo:nil
repeats:YES];
}
}
- (void)_timerFired:(NSTimer *)timer {
if ([_timer isValid]) {
[self showPopupWithStyle:CNPPopupStyleFullscreen];
[_timer invalidate];
}
_timer = nil;
NSLog(#"ping");
}
If you want to restart the timer just add this code where you'd like the action to start back up.
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self
selector:#selector(_timerFired:)
userInfo:nil
repeats:YES];
}
Hope this helps! :)

Fire IBAction automatically

I have a button and want to fire it automatically by itself without touch.
Is it possible?
-(IBAction)xxx:(id)sender
My answer assumes you have the method:
- (IBAction)someAction:(UIButton *)sender {
}
and that you have a reference to the button in an instance variable named someButton.
If you just need to "fire it" now, simply call it:
[self someAction:someButton];
If you need to "fire it" once, but later, you can do:
// call it 5 seconds from now
[self performSelector:#selector(someAction:) withObject:someButton afterDelay:5.0];
If you want to fire it repeatedly, use a timer:
myTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(buttonTimerFired) userInfo:nil repeats:YES];
- (void)buttonTimerFired {
[self someAction:someButton];
}
Action can be called like every regular function - you can do it by running a timer on something else.
You should use NSTimer for doing your work.
[NSTimer scheduledTimerWithTimeInterval: 0.01f target: self selector: #selector(BtoonMethod) userInfo: nil repeats: NO];
-(void)BtoonMethod
{
// write code for call yor button method
}

Why memory consumption grows?

Here is a very simple piece of code:
- (void)functionOne
{
[self performSelector:#selector(functionTwo) withObject:nil afterDelay:1.0];
}
- (void)functionTwo
{
[self performSelector:#selector(functionOne) withObject:nil afterDelay:1.0];
}
As you can see there's nothing in these two methods what could cause growth of memory consumption. But it grows. Very slowly, but it does. About 0.01 MB every three seconds. Why? How can i avoid it?
You are effectively creating an infinite loop. If you want to switch the state of an object every one second (as you said in the comments), do it this way:
Create a method like so:
- (void)functionOne
{
if( [obj isEqual:stateA] ) {
obj = stateB;
} else {
obj = stateA;
}
}
and call it with a timer:
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(functionOne) userInfo:nil repeats:YES];
to avoid infinite loops you should use a NSTimer and one function, in which you toggle the state of your object.
in your init method, or something like viewDidLoad you should start a timer like
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(switchState:)
userInfo:nil
repeats:YES];
}
then you use one method like
- (void) switchState:(NSTimer *)timer {
if ([[self yourState] isEqual:stateOne]) {
[self setYourState:stateTwo];
} else {
[self setYourState:stateOne];
}
}
for more information see http://developer.apple.com/library/ios/#documentation/cocoa/reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html
The memory grows simply because the Application needs to hold onto some state. Each time you call perform selector that selector is pushed onto the stack. This stack is saved in memory. Hence the growth.

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]]

Cocoa Touch - Timers

How can I make a timer that counts down from 3 and then runs a method? How would I do that?
Is that different from a timer counting from 0 to 3? It will still wait three seconds, either way.
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(myMethod:) userInfo:nil repeats:NO];
Better way might be to use performSelector:withObject:afterDelay: method:
[self performSelector:#selector(myMethod) withObject:nil afterDelay:3.0f];
Or in case method takes 1 parameter:
[self performSelector:#selector(myMethod:) withObject:parameter afterDelay:3.0f];
If method takes multiple parameters you'll need to use NSInvocation class
- (void) handleTimer: (NSTimer *) timer
{
do some work here...
} // handleTimer
// at some point in your controller
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: 3.0
target: self
selector: #selector(handleTimer:)
userInfo: nil
repeats: NO];