Method selector pointing at different object - objective-c

The following method is in a viewController.
refreshTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(refreshLabels) userInfo:nil repeats:YES];
Is it possible to select a method inside appDelegate (or another class) at the selector instead of in the current object?
like:
AppDelegate *ad = (AppDelegate *) [[UIApplication sharedApplication] delegate];
refreshTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector([ad refreshLabels]) userInfo:nil repeats:YES];
Thanks!

try this.
AppDelegate *ad = (AppDelegate *) [[UIApplication sharedApplication] delegate];
refreshTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:ad selector:#selector(refreshLabels) userInfo:nil repeats:YES];
in your AppDelegate, there should be a declared refreshLabels method,
target
The object to which to send the message specified by aSelector when the timer fires. The target object is retained by the timer and released when the timer is invalidated.
aSelector
The message to send to target when the timer fires. The selector must correspond to a method that returns void and takes a single argument. The timer passes itself as the argument to this method.
the code in your question set 'self' as argument for target, but the method you are trying to call is in the AppDelegate

Related

How can I stop a NSTimer from being called over and over again

I have a generated Subview that can be moved around. Every time it moves I check if it's passed 300 on the X-axis. My problem is, that when it passes the point and you don't stop moving it, the NSTimer gets started so often, that the program crashes.
NSArray *subviews = [self.view subviews];
for (UIView *subview in subviews) {
if (subview.frame.origin.x > 300) {
NSMutableArray *data = [[NSMutableArray alloc] initWithCapacity:1];
[data addObject:subview];
[NSTimer scheduledTimerWithTimeInterval:3.00 target:self selector:#selector(callFunction:) userInfo:data repeats:NO];
}
}
You should keep a reference to NSTimer instances and when you don't want it to be fired anymore you can call -[NSTimer invalidate]
Update besides, is it your intentions to schedule timers in a loop?
Add a property where you save a reference to the timer. So you can always check if NSTimer is already started and you stop it by
[NSTimer invalidate];
you add a property #property(nonatomic, strong) NSTimer *timerand then you can check like:
if(!self.timer){
self.timer = [NSTimer scheduledTimerWithTimeInterval:3.00 target:self selector:#selector(callFunction:) userInfo:data repeats:NO];
}
Try This :
[NSTimer invalidate];
NSTimer = nil;

Stop immediately NSTimer

I'm trying to stop my NSTimer (no repeats) immediately but i can't.
my NSTimer do the following code:
-(void)timerAction:(NSTimer*)timer{
dispatch_queue_t serverDelaySimulationThread = dispatch_queue_create("com.xxx.serverDelay", nil);
dispatch_async(serverDelaySimulationThread, ^{
[NSThread sleepForTimeInterval:2.0];
dispatch_async(dispatch_get_main_queue(), ^{
//CALL WEBSERVICE RESPONSE IN HERE
});
});
}
Each time textField Did Change, i will invalidate NSTimer and recreate NSTimer!! All i want to execute a request to WEBSERVICES if the Delay time between 2 times user typing characters bigger than 2s. My code is following
-(void) textFieldDidChange:(id)sender{
[MyTimer invalidate];
MyTimer = nil;
MyTimer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:#selector(timerAction:) userInfo:nil repeats:NO];
}
But, when i quickly type "ABCD" -> 2s after that, 4 webservices was called.
How can i stop NSTimer while it unfinished
Tks for advance!
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
[myTimer invalidate];
myTimer = nil;
myTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(timerFired) userInfo:nil repeats:NO];
return YES;
}
This worked for me.
Your timer timeInterval is set to 0. So each time you type your timer fires. Change your code to look like this
MyTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self selector:#selector(timerAction:) userInfo:nil repeats:NO];
And it should work :)
The problem is you are implementing textdidchange delegate. So how many times you type text. It will get called. SO inside that you have written four letters. So definitely your NSTimer is calling four times your web service. I would suggest better to use - (void)controlTextDidEndEditing:(NSNotification *)aNotification So that whenever you enter or tabb out your webservice will called.

Pass method as argument

can I pass a method as an argument?
I don't succeed to pass the method targetOpenView in the example below:
-(void) targetTimeView:(id)sender {
[self TimeViewWithtimeInterval:.6 selector:targetOpenView]; //targetOpenView does NOT work
}
-(void) timeViewWithtimeInterval:(float)interval selector:openViewMethod{
[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:#selector(openViewMethod) userInfo:nil repeats:NO];
}
Any suggestions how I could make this work? Thanks!
You need the #selector compiler directive to extract the select from a method name, like you did when creating the timer:
[self TimeViewWithtimeInterval:.6 selector:#selector(targetOpenView)];
And define your argument to the type SEL:
-(void) TimeViewWithtimeInterval:(float)interval selector:(SEL)openViewMethod
{
...
}
Then, when passing the argument to the NSTimer method you can leave off the #selector since the type is already a selector:
[NSTimer scheduledTimerWithTimeInterval:interval target:self
selector:#selector(openViewMethod) /* here */
userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:interval target:self
selector:openViewMethod /* pass it directly */
userInfo:nil repeats:NO];

When use NSTimer in classA then can't call any method from other place

Here is a code I call to run timer for calling "tick:" method in classA (it calls NOT in main thread):
- (id)init {
self = [super init];
if (self != nil) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0f
target:self selector:#selector(tick:) userInfo:nil repeats:YES];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[currentRunLoop run];
}
return self;
}
And timer works great.
But when try to access to "doSomething" method (the same instance of class classA) in the same thread then method "doSomething" does't calls.
Why? How to fix the problem?
How selector doSomething: is called?
Anyway you should try [classAinstance performSelectorOnMainThread:#selector(doSomethingOnMainThread:) waitUntilDone:YESORNO];

How to pass an argument to a method called in a NSTimer

I have a timer calling a method but this method takes one paramether:
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:#selector(timer) userInfo:nil repeats:YES];
should be
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:#selector(timer:game) userInfo:nil repeats:YES];
now this syntax doesn't seems to be right. I tried with NSInvocation but I got some problems:
timerInvocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(timer:game)]];
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
invocation:timerInvocation
repeats:YES];
How should I use Invocation?
Given this definition:
- (void)timerFired:(NSTimer *)timer
{
...
}
You then need to use #selector(timerFired:) (that's the method name without any spaces or argument names, but including the colons). The object you want to pass (game ?) is passed via the userInfo: part:
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
target:self
selector:#selector(timerFired:)
userInfo:game
repeats:YES];
In your timer method, you can then access this object via the timer object's userInfo method:
- (void)timerFired:(NSTimer *)timer
{
Game *game = [timer userInfo];
...
}
As #DarkDust points out, NSTimer expects its target method to have a particular signature. If for some reason you can't conform to that, you can instead use an NSInvocation as you suggest, but in that case you need to fully initialise it with the selector, target and arguments. Eg:
timerInvocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:#selector(methodWithArg1:and2:)]];
// configure invocation
[timerInvocation setSelector:#selector(methodWithArg1:and2:)];
[timerInvocation setTarget:self];
[timerInvocation setArgument:&arg1 atIndex:2]; // argument indexing is offset by 2 hidden args
[timerInvocation setArgument:&arg2 atIndex:3];
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
invocation:timerInvocation
repeats:YES];
Calling invocationWithMethodSignature on its own doesn't do all that, it just creates an object that is able to be filled in in the right manner.
You can pass NSDictionary with named objects (like myParamName => myObject) through userInfo parameter like this
theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
target:self
selector:#selector(timer:)
userInfo:#{#"myParamName" : myObject}
repeats:YES];
Then in timer: method:
- (void)timer:(NSTimer *)timer {
id myObject = timer.userInfo[#"myParamName"];
...
}