I am trying to invoke a function that contains ccactioninterval in Cocos3d. I want to call that function at specific time intervals.When I tried NSTimer , i found that it works sometimes and sometimes not.
NSTimer makeTarget=[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
Here createTargets is the function that contains action events. when i run the function straightit works fine for single time. Problem comes when i try to schedule it. I ve tried different methods already explained for related questions . But nothing worked for me. . . .
Here is the code
-(void) addTargets {
NSTimer *makeTarget = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
}
-(void)createTargets {
CC3MeshNode *target = (CC3MeshNode*)[self getNodeNamed: #"obj1"];
int minVal=-5;
int maxVal=5;
float avgVal;
avgVal = maxVal- minVal;
float Value = ((float)arc4random()/ARC4RANDOM_MAX)*avgVal+minVal ;
[target setLocation:cc3v(Value, 5.0, 0.0)];
CCActionInterval *moveTarget = [CC3MoveBy actionWithDuration:7.0 moveBy:cc3v(0.0, -10.0, 0.0)];
CCActionInterval *removeTarget = [CCCallFuncN actionWithTarget:self selector:#selector(removeTarget:)];
[target runAction:[CCSequence actionOne:moveTarget two:removeTarget]];
}
-(void)removeTarget:(CC3MeshNode*)targ {
[self removeChild:targ];
targ=nil;
}
Without much code its hard to tell what you issues is, but here are some things to try apologies if any of this is obvious.
Are you holding onto a reference to the timer?
This might be useful for debugging. If you have a property called makeTargetTimer, then you could do this:
NSTimer * makeTargetTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
self.makeTargetTimer = makeTargetTimer // Save to a property for later use (or just use an iVar)
The only way to stop a re-occurring timer is to invalidate it. Therefore you could check to see if its been invalidated.
BOOL isInvalidated = [self.makeTargetTimer isValid];
Also you might want to do this in your dealloc method anyway:
- (void) dealloc {
[_makeTargetTimer invalidate]; // Stops the timer from firing (Assumes ARC)
}
Are you scrolling when the even should be received?
If you want the timer to be fired while scrolling then you need to use NSRunLoopCommonModes. There is a excellent expiation in this question.
[[NSRunLoop currentRunLoop] addTimer:makeTargetTimer forMode:NSRunLoopCommonModes];
What is your implementation of createTargets like?
Have you put NSLog statements on the body of this method. Are you certain its not being called?
Related
I am using an NSTimer to call a method which is titled Lose. I had a timer which when it ran out, it called Lose, but I lost everything due to a hard drive error. After trying to code it all again, I can't seem to get the method to be called.
Timer = [NSTimer timerWithTimeInterval:timeMax target:self selector:#selector(Lose) userInfo:nil repeats:NO];
Lose is declared in my .h file, like this:
-(void)Lose;
Also, my method looks like this:
-(void)Lose{
Text.hidden = NO;
scoreLabel.hidden = NO;
Target.hidden = YES;
Targetx.hidden = YES;
if (Score > highScoreNumber) {
highScoreAchieved.hidden = NO;
highScoreNumber = Score;
}
}
The variable timeMax is an int declared in my .h file, like last time.
whenever a target is tapped in my game, timeMax becomes .03 seconds shorter. I do it like this:
timeMax = 5 - (Score * 0.03);
I don't remember it looking different before the massive hardware failure, but why isnt it working?
You have to schedule the timer on a run loop or just use this line instead which schedules it for you:
Timer = [NSTimer scheduledTimerWithTimeInterval:timeMax
target:self
selector:#selector(Lose)
userInfo:nil
repeats:NO];
It's also a good idea to always back up your code...which reminds me.
I am working on an iOS app which provides/makes calls from app. We can make two calls one after another. First time we are making 1st call. Once call get established, the NSTimer should be fired and it would show the duration of the call.
For this I am doing following for timer
self.switchTimer1 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(setTimerLabel1:)
userInfo:nil
repeats:YES];
[self.switchTimer1 fire];
after establishing this first call, user can make second call.
Once second call gets established, it would fire second timer.
if (hasSecondCall)
{
self.switchTimer2 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(setTimerLabel2:)
userInfo:nil
repeats:YES];
timeSec=0;
timeMin=0;
[self.switchTimer2 fire];
}
It's working fine while making first time of both calls.
Suppose if I ended 2nd call and again I made call, that time 2nd timer before establishing the call the timer automatically calling and once call established, the timer incrementing value very fast like double values showing. Like, 2,4, 6, etc.
For secondtimer after firing method following
- (void)setTimerLabel2:(NSTimer *)timer {
timeSec=timeSec+1;
NSLog(#"timeSec+1 %d",timeSec+1);
if (timeSec == 60)
{
timeSec = 0;
timeMin=timeMin+1;
}
NSString* timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
[_switchCallLCD setStatus:timeNow labelNumber:2];
}
While disconnecting call we calling following
- (void)endingCallWithId:(UInt32)call_id {
if (hasSecondCall&& call_id==_current_call) {
if (self.switchTimer2) {
//NSLog(#"self.predictNumber %#",self.predictNumber);
self.predictNumber=self.predictNumber2;
[_lcd setText:self.predictNumber];
[self.switchTimer2 invalidate];
self.switchTimer2 = nil;
[self.switchTimer2 release];
[_switchCallLCD setStatus:NSLocalizedString(#"call ended",nil) labelNumber:2];
timeSec = 0;
timeMin = 0;
}
I have searched so many forums regarding this issue, but I couldn't figure out solution. I heard, if we use multiple timers there is some issue like this.
You likely still have the previous instance of the timer(s) running. When you make a second set of calls you then have 2 instances of switchTimer1 running and 2 instances of switchTimer2 running.
As soon as you end a call, you need to invalidate the timer:
[self.switchTimer1 invalidate];
and then set it to nil for good measure:
self.switchTimer1 = nil;
I am fairly new to objective-c and iOS programming in Xcode, and while making my first app I ran into the problem of creating barriers around the edge of the screen which the object cannot pass through. I tried placing objects at the boundary and using CGRectIntersectsRect, but the collision between the boundary and the main object is not registered. Does anyone know how I would go about in doing this?
this is the code that I have used for the object's movement:
const float rate= 0.025;
NSTimer *goLeft;
NSTimer *goRight;
- (IBAction)right {
goRight=[NSTimer scheduledTimerWithTimeInterval:rate
target:self
selector:#selector(goRight)
userInfo:nil
repeats:YES];
if (goRight == nil){
goRight=[NSTimer scheduledTimerWithTimeInterval:rate target:self selector:#selector(goRight) userInfo:nil repeats:YES];
}
}
- (IBAction)left{
goLeft=[NSTimer scheduledTimerWithTimeInterval:rate
target:self
selector:#selector(goLeft)
userInfo:nil
repeats:YES];
if (goLeft == nil){
goLeft=[NSTimer scheduledTimerWithTimeInterval:rate target:self selector:#selector(goLeft) userInfo:nil repeats:YES];
}
}
-(IBAction)stopLeft{
[goLeft invalidate];
goLeft=nil;
}
-(IBAction)stopRight{
[goRight invalidate];
goRight=nil;
}
-(void)goLeft{
_userToken.center =CGPointMake(_userToken.center.x -20, _userToken.center.y);
}
-(void)goRight{
_userToken.center =CGPointMake(_userToken.center.x +20, _userToken.center.y);
}
And for collision with object at left border (userToken and friendly are both UIImageView). However when they collide NSLog is not executed.
-(void)checkForCollision{
if (CGRectIntersectsRect(_userToken.frame, _friendly.frame)){
NSLog(#"Left Intersect");
}
}
You don't say what _userToken.frame and _friendly.frame are set to when you test - it's a good idea to log them while testing so you can manually verify.
An alternative approach, if the valid screen area is a rect, is to check the intersection of the token and the valid area and verify that it is equal to the token frame:
if (CGRectEqualToRect(CGRectIntersection(_userToken.frame, validFrame), _userToken.frame)) { ...
It's important when checking by any method that the frames are in the same coordinate space (that the views have the same superview, or that you convert them to the same common superview) - again, logging will help you to verify this.
Aside:
Trying to recreate the timer if it just failed is unlikely to help. And you should really check for an existing timer and invalidate it before creating a new timer (otherwise you could end up with multiple timers running and no way to stop them).
I have surfed on a bunch of resources from the internet but still couldn't get any idea of what I'm trying to implement.
I would like to record user preferences by detecting how much time they have stayed in each information pages.
In order to make this question simpler, that says I have a entrance page with 5 different theme pages which represent different information.
I would like to know which page is the page that user most interesting.
What I wish to do is to put a counter in each theme pages and calculate how much time they stay in that page (the counter should be able to pause for reentrance), and then when I press a button on the entrance page, an alert will tell me which page is the page that user spent most of time on it.
I hope this make sense!
Does anyone have any experience on this? I would be most appreciative if anyone can provide some codes and examples for me.
ViewController A:
- (void)viewDidLoad {
[super viewDidLoad];
//create iVar of NSInteger *seconds
seconds = 0;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(increaseTimeCount) userInfo:nil repeats:YES];
[timer fire];
}
- (void)increaseTimeCount {
seconds++;
}
- (void)dealloc {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// you can add to array too , if you want and get average of all values later
[defaults setInteger:seconds forKey: NSStringFromClass(self)];
}
now in Entrance View ..
get the time as
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger *secondsInView = [defaults integerForKey:NSStringFromClass(View1ClassName)];
Firstly I'd like to draw your attention to the Cocoa/CF documentation (which is always a great first port of call). The Apple docs have a section at the top of each reference article called "Companion Guides", which lists guides for the topic being documented (if any exist). For example, with NSTimer, the documentation lists two companion guides:
Timer Programming Topics for Cocoa
Threading Programming Guide
For your situation, the Timer Programming Topics article is likely to be the most useful, whilst threading topics are related but not the most directly related to the class being documented. If you take a look at the Timer Programming Topics article, it's divided into two parts:
Timers
Using Timers
For articles that take this format, there is often an overview of the class and what it's used for, and then some sample code on how to use it, in this case in the "Using Timers" section. There are sections on "Creating and Scheduling a Timer", "Stopping a Timer" and "Memory Management".There are a couple of ways of using a timer. From the article, creating a scheduled, non-repeating timer can be done something like this:
1) scheduled timer & using selector
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:#selector(onTick:)
userInfo: nil repeats:NO];
if you set repeats to NO, the timer will wait 2 seconds before
running the selector and after that it will stop;
if repeat: YES, the timer will start immediatelly and will repeat
calling the selector every 2 seconds;
to stop the timer you call the timer's -invalidate method: [t
invalidate]; As a side note, instead of using a timer that doesn't
repeat and calls the selector after a specified interval, you could
use a simple statement like this:
[self performSelector:#selector(onTick:) withObject:nil afterDelay:2.0];
this will have the same effect as the sample code above; but if you want to call the selector every nth time, you use the timer with repeats:YES;
2) self-scheduled timer
NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
interval: 1
target: self
selector:#selector(onTick:)
userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
this will create a timer that will start itself on a custom date
specified by you (in this case, after a minute), and repeats itself
every one second
3) unscheduled timer & using invocation
NSMethodSignature *sgn = [self methodSignatureForSelector:#selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:#selector(onTick:)];
NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
invocation:inv
repeats:YES];
and after that, you start the timer manually whenever you need like this:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
And as a note, onTick: method looks like this:
-(void)onTick:(NSTimer *)timer {
//do smth
}
Try this simple method:
- (void)viewDidLoad
{
[super viewDidLoad];
count = 0; // Declare int * count as global variable;
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerAction) userInfo:nil repeats:YES];
}
- (void)timerAction
{
[self custom_method:count++]
}
Might I suggest a different route. If you take the time since reference date, when the user enters the page:
NSTimeINterval time = [NSDate timeIntervalSinceReferenceDate]
then do the same when they leave the page and compare them.
timeOnPage = time - time2;
This is much more efficient than firing a timer on another thread unnecessary.
You do not need to use NSTimers for this at all.
Store the date/time when the user starts viewing, and calculate the time difference when they stop viewing using simple time arithmetic.
Exactly As Dave Wood says You should use date and time for starting and ending viewing that screen and calculate the difference and then save it to any integer variable.Using NSTimer will make the performance effect in your app and make the compiler busy while incrementing the count.
Is there any method (like – viewDidLoad) to continuously execute a part of code? I need to be able to check a value on a remote server continuously.
The way you would do this is to set up an NSTimer.
-(void)startCheckingValue
{
mainTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(checkValue:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:mainTimer forMode:NSDefaultRunLoopMode];
}
-(void)checkValue:(NSTimer *)mainTimer
{
//Placeholder Function, this is where you write the code to check your value on the remote server
}
The timerWithTimeInterval function is the one that you are interested in, the main things that you need to pass it, as you see above, are the interval at which it will execute the function whose selector you pass it. The time interval is in seconds, so it is currently set to check every second, which is probably way too fast.
Use an NSTimer to execute the same block of code every x seconds. However, I don't think that's what you want, given that it would put a lot of extra load on the server and you might get banned, so there's probably a better way.
apple's page on NSTimer use
You ned to use NSTimer For this:
in your interface declare a NSTimer object like:
NSTimer *timer;
in your .m viewDidLoad method add the below line.
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:YES];
In the timerFireMethod method you need to do the server calling and other stuffs.