Feasibility for adding value to a NSTimer - objective-c

I am currently making a application using NSTimer as base for recording time. However, in the event that the player used a hint or forfeit on the current question, I would like to have a penalty of increasing time to the on-going NSTimer.
The question I have is, is it possible to add in more value to the on-going NSTimer?
e.g The timer is at 0:23:41.2, and the user press hint/forfeit. I want to have a function that add, lets say 10min. How do I make a function such that the timer will become 0:33:41.2 when the player press hint/forfeit?
I tried finding on google and SO on articles related to NSTimer and came across this SO thread which might be useful. How to value for NSTimer
Instead of elapse time as shown in the thread, I think I could swap it with a variable like below. (But if the example I shown below is not feasible, please enlighten me. I really want to make this game a successful one)
-(BOOL)hintButtonPressed
.
-(void) timerFireMethod:(NSTimer *) theTimer {
if (hintButtonPressed == true) {
// do something to increase value
[theTimer invalidate];
}
}

Even though I would not use a NSTimer for a countdown, there is an easy way to add time to its fireDate:
[_timer setFireDate:[[_timer fireDate] dateByAddingTimeInterval:600]];
This would add 10 minutes (600 seconds) to my _timer.
And the best solution for your example would be to create an action-method for the button and check in that action-method whether the user already got a time bonus.
Of course you can modify the fireDate in the fire method but it won't fire again with my codeline.

NSTimer is not a good tool for tracking time. It's a good tool for scheduling periodic actions (particularly actions that don't have very tight timing requirements).
The way you track time is with three ivars: the most recent "timer start" time, the "accumulated time" (which is the time prior to the most recent start), and an "isRunning" boolean. At any given time, the total time is:
accumulated + (now - start) * (isRunning ? 1 : 0)
With this, you can easily add or subtract time by modifying accumulated. And you don't need an NSTimer to update your data (which is seldom a good approach).

To what i remember, you can't add, increment time to a NSTimer, you need to create a new one, and release / invalidate the older one.
By the way, if it's a simple timer, you still can make it easy
[NSObject cancelPreviousPerformRequestsWithTarget: self]
[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay: incrementedTime];
But you if you performSelector, you cant get precise time information like NSTimer, you can just blind increment time. So all depend of your needs.

Related

Is there a simple way (in Cocoa/iOS) to queue a method call to run once in the next run loop?

UIView has a setNeedsDisplay method that one can call several times within the same event loop, safe in the knowledge that the redrawing work will happen soon, and only the once.
Is there a generic mechanism for this sort of behaviour Cocoa? A way of of saying, "Queue a selector as many times as you like, when it's time, the selector will run once & clear the queue."
I know I could do this with some kind of state tracking in my target, or with an NSOperationQueue. I'm just wondering if there's a lightweight approach I've missed.
(Of course, the answer may be, "No".)
setNeedsDisplay is not a good example of what you're describing, since it actually does run every time you call it. It just sets a flag. But the question is good.
One solution is to use NSNotificationQueue with NSNotificationCoalescingOnName.
Another solution is to build a trampoline to do the coalescing yourself. I don't have a really good blog reference for trampolines, but here's an example of one (LSTrampoline). It's not that hard to build this if you want to coalesce the messages over a period of time. I once built a trampoline with a forwardInvocation: similar to this:
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:self.target];
[invocation retainArguments];
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeout invocation:invocation repeats:NO];
}
This actually coalesces all messages to the object over the time period (not just matching messages). That's all I needed for the particular problem. But you could expand on this to keep track of which selectors are being coalesced, and check your invocations to see if they match "sufficiently."
To get this to run on the next event loop, just set timeout to 0.
I keep meaning to blog about trampolines. Required shilling: My upcoming book covers trampolines in Chapter 4 and Chapter 20.
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(doTheThing:)
object:someObject];
[self performSelector:#selector(doTheThing:)
withObject:someObject
afterDelay:0];
This is not exactly how UIView is doing it because setNeedsDisplay simply sets a flag and the internal UIView mechanism makes sure to call drawRect: after setting up the drawing environment, but this is a generic way and doesn't require any special state tracking in your class.

Removing Object With Timer

I have two NSMutableArrays, collectables and collectableViews.
My app consists of a character moving around and gathering collectables (coins, apples, bananas, etc) for points...
I would like the collectables to disappear after a certain amount of time.. however, I am confused as to where to put an NSTimer to not disrupt Model/View/Controller design.
For example, If I put an individual timer in each model, the model doesn't know of the view and cannot remove the view..
If I put the NSTimer in the controller, I would need to make another array consisting of all the collectables on the screen, in order of which one expires first. The timer's method would fire every second and remove each collectable when they are due.
Is there an easier, better way to do this?
Most games model this kind of 'state-monitoring' using one or more game clocks. You can do something like this:
Create a data structure containing a duration time, function
pointer, and array of object variables. For this example let's call
it DecayEvent.
Create a static, mutable array of DecayEvent's in your front (main)
controller, with some nice accessor methods
Choose an appropriate event processing interval. It needs to be
large enough to process what you think the maximum number of events
will be, but small enough not to retard user experience.
Create a method on your front controller that will process through
the array of decay events. Every time the method is called it will
iterate the array and decrement the event's duration time by the
event processing interval. If the decay events duration falls below
zero then 'fire the event' (basically, trigger its callback function
in another thread, with the callback arguments).
Create an NSTimer in your main thread. Set it to call your
processing method at every event processing interval.
You will have to tweak quite a bit to get everything working the way you want, but the steps above will generally work.
Good luck!
Your current situation tends that you should keep timer in your controller because controller has access to each data modal and views you can access arrays too. also another approach is to use NSNotificationCenter. First try and if that doesn't work then let us know.

Idle thread approach in iOS

I'm trying to set up a thread that stays idle until new data it's available. What it's the best approach for this in Objective-C? Till now I tried to make a simple run loop
while(YES) {
if(isDataAvailable) {
//process data
}
}
However this has an huge impact on performance, my FPS drops from 40 to 20 and the interface becomes unusable (even if the actual data process happens once in a second or so and it's not very intense for the CPU. I tried to add [NSThread sleepForTimeInterval:0.01] at the end, but this way I lose data packages ('process data' refers to some streaming related operations, queue and unqueue data packages), however the FPS returns to normal.
I'm fair new in Objective-C and I was thinking maybe there is a better way to do this? I also had a look over NSRunLoop, but didn't manage to make it work as a run loop :), only attached a timer to it that doesn't do more than my [NSThread sleepForTimeInterval:0.01] thing.
Any help it's highly appreciated:D
If you need to keep the seconary thread alive, you definitely want to use a real runloop:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1
Basically, just create and start your thread, set up an autorelease pool, then run your runloop for some set time amount. When the time expires, you check to see if you should exit your thread, or enter into the runloop again.
As Marcelo points out though, there are more modern approaches to achieve concurrency (GCD and async dispatch being a couple of examples) so maybe investigate other forms of concurrency as well.

NSTimer issue - Stop different timers using single functions

I am creating an application in that I need to use about 20 different Timers.
But all the timers are going to be created at run time, by calling some function.
All the timers might having different timer interval and all timer do have different counters that will be reduced by one with passing of 1 minute.
Now when the counter will become 0 the timer will be stopped. But in my application all timers have different counter values and I want to stop different timers at it's time interval using a single function.
I know that we can create different timers and by providing the selector values to their respective timer functions , we can stop the timer by I don't have idea that how many timers are running at a time , and if I do stop a single timer at a time then it will lead to stop all the timers and the functionality is not showing properly.
Please help me by providing any logic or samples How to stop multiple timers using single function at different time interval.
thanks in advance
I think you may want to reconsider your software design. You can call your method as normal:
[self method];
And then at the end of each method, do the following:
[self performSelector:#selector(method) withObject:nil afterDelay:(1000)];
This will create a loop. You can then increment an integer and do something else when that counter reaches 0. You'll be able to manage your code much more effectively. You may still need timers for some situations, but this will definitely be more efficient than the 20 timers you were planning on using.

order of execution in run loop

I am using [NSTimer scheduledTimerWithInterval:selector:#selector(loop):repeats:YES] to create a neverending loop with -loop() being called every interval. My viewcontroller also has a -touchesBegan to process UITouch's.
Suppose the screen is touched and a UIEvent is fired, does the code in -touchesBegan execute first in the run loop or the code in the -loop called by NSTimer execute first?
It's explained in this Apple document.
However, it's not that useful. NSTimer is not a real-time mechanism, and you can't predict exactly when it fires. It will also depend how often iOS registers touch events, and how often you configure the timer to fire. It would be a very, very, very bad idea to write a code which depends on these subtleties and features buried deep in the documentation I just cited.
Write code which doesn't depend on what you just asked.