Mark and check a process if it's completed or not - iphone

I'm not sure how to write this line. What I'm looking to do is write one statement that is only done once and upon completion marks itself to not be done again(To avoid a constant loop) for something like a day time and night time.
What I think needs to be written:
if ([nightTime timeIntervalSinceNow] <= 0 && "check if already reset or not"){
// The following process has to be done, but only once
// reset dayTime (for tomorrow)
// stop the current NSTimer
// recreate a new NSTimer for nightTime
}
Can anyone point me in the right direction of what I should use?
Many thanks!

Take one flag iIsProcessDone
if ([nightTime timeIntervalSinceNow] <= 0 && !iIsProcessDone){
iIsProcessDone = YES;
// The following process has to be done, but only once
// reset dayTime (for tomorrow)
// stop the current NSTimer
// recreate a new NSTimer for nightTime
}
And reset it when you want to call this process again.

Related

Trying to program a timer to do something when it reaches 5 seconds

I can't seem to figure out what to do here. I'm creating a learn to type game where if the user doesn't get the word correct in 5 seconds, they lose a life.
Either this could be implemented by counting down to 0 from 5, or counting up to 5.
I tried using the stopwatch for c# system diagnostics, which works for everything except I can't figure out how to check when it hits 5 seconds. It is a time object you cant compare it to an int.
you have two options here.
You can check the time in the Update function with Time.time or Time.deltaTime, or you can use a Coroutine with the new WaitForSeconds(5) object.
It could be as simple as:
float time;
void Update()
{
time += Time.deltaTime;
if(time > 5)
{
LoseALife();
}
}
If you need to restart the timer each time you complete a word you might have an aditional method like:
public void RestartTimer()
{
time = 0;
}
This would make the timer go back to 0 any moment you need it.

Timer not firing every second on WatchKit

This timer isn't firing every second, when I check the log and UI it seems to be firing every 3-4 seconds.
func startTimer() {
print("start timer")
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(timerDidFire),
userInfo: nil,
repeats: true)
}
func timerDidFire(timer: Timer) {
print("timer")
updateLabels()
}
Is this just something that is going to happen on the Watch due to lack of capabilities, or is there something wrong in my code?
Here is the log if needed:
0.0396000146865845
3.99404102563858
7.97501903772354
11.9065310359001
EDIT:
And for clarification, what I'm updating every second is the workout timer, so it needs to be updated every second that ticks by.
If your app is busy doing something else, which blocks or delays the run loop from checking that the fire time has repeatedly passed, the timer will only fire once during that period:
A repeating timer always schedules itself based on the scheduled firing time, as opposed to the actual firing time. For example, if a timer is scheduled to fire at a particular time and every 5 seconds after that, the scheduled firing time will always fall on the original 5 second time intervals, even if the actual firing time gets delayed. If the firing time is delayed so far that it passes one or more of the scheduled firing times, the timer is fired only once for that time period; the timer is then rescheduled, after firing, for the next scheduled firing time in the future.
As an aside, it may be more efficient to update your UI based on a response to a change (e.g., observation), or reaction to an event (e.g., completion handler).
This avoids creating busy work for the app when it's driven to check yet doesn't actually have a UI update to perform, if nothing has changed during the timer interval.
It also prevents multiple changes within the fire interval from being ignored, since a timer-driven pattern would only be displaying the last change in the UI.
Consider using a WKInterfaceTimer label in place of the label that you are using to show the timing:
A WKInterfaceTimer object is a special type of label that displays a
countdown or count-up timer. Use a timer object to configure the
amount of time and the appearance of the timer text. When you start
the timer, WatchKit updates the displayed text automatically on the
user’s Apple Watch without further interactions from your extension.
Apple Docs.
WatchOS will then take responsibility for keeping this up-to-date. The OS handles the label for you, but you have to keep track of the elapsed time: you just need to set an NSDate to do that (see example below).
Sample Code.
In your WKInterfaceController subclass:
// Hook up a reference to the timer.
#IBOutlet var workoutTimer: WKInterfaceTimer!
// Keep track of the time the workout started.
var workoutStartTime: NSDate?
func startWorkout() {
// To count up use 0.0 or less, otherwise the timer counts down.
workoutTimer.setDate(NSDate(timeIntervalSinceNow: 0.0))
workoutTimer.start()
self.workoutStartTime = NSDate()
}
func stopWorkout() {
workoutTimer.stop()
}
func workoutSecondsElapsed() -> NSTimeInterval? {
// If the timer hasn't been started then return nil
guard let startTime = self.workoutStartTime else {
return nil
}
// Time intervals from past dates are negative, so
// multiply by -1 to get the elapsed time.
return -1.0 * self.startTime.timeIntervalSinceNow
}
Comprehensive blog entry: here.
As of 2021, the (Foundation) Timer object supports a tolerance variable (measured in seconds). Set timer.tolerance = 0.2, and you should get a fire every second (+/- 0.2 seconds). If you are just updating your GUI, the exact time interval isn't that critical, but this should be more reliable than using no tolerance value. You'll need to create the timer separately, and manually add to the run queue such as below... (Swift)
import Foundation
// Set up timer to fire every second
let newTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in
self.timerFired()
}
newTimer.tolerance = 0.2 // For visual updates, 0.2 is close enough
RunLoop.current.add(newTimer, forMode: .common)

How to Correctly Destroy ToneUnit after Tone Fades Out?

I'm generating tones on iPhone using AudioUnits based on Matt Gallagher's classic example. In order to avoid the chirps and clicks at the beginning/end, I'm fading the amplitude in/out in the RenderTone callback. I'd like to destroy the ToneUnit at the end of the fade out, that is, after the amplitude reaches zero. The only way I can think to do this is to call an instance method from within the callback:
if (PlayerState == FADING_OUT) {
amplitude -= stepsize;
if (amplitude <= 0) {
amplitude = 0;
PlayerState = OFF;
[viewController destroyToneUnit];
}
}
Unfortunately this is more challenging that I had thought. For one thing, I still get the click at the end that the fadeout was supposed to eliminate. For another, I get this log notice:
<AURemoteIO::IOThread> Someone is deleting an AudioConverter while it is in use.
What does this message mean and why am I getting it?
How should I kill the ToneUnit? I suspect that the click occurs because RenderTone and destroyToneUnit run on different threads. How can I get these synchronized?
In case it's helpful, here's my destroyToneUnit instance method:
- (void) destroyToneUnit {
AudioOutputUnitStop(toneUnit);
AudioUnitUninitialize(toneUnit);
AudioComponentInstanceDispose(toneUnit);
toneUnit = nil;
}
If I NSLog messages right before and right after AudioUnitUninitialize(toneUnit);, the notice appears between them.
I also ran into the same issue. When I called the destroyToneUnit from the main thread, the warning went away.
[viewController performSelectorOnMainThread:#selector(destroyToneUnit) withObject:nil waitUntilDone:NO];

Time Delay for a process in Unity 3D

I have to give the delay for the process to happen, which I am calling in the Update function.
I have tried CoUpdate workaround also. Here is my code:-
function Start()
{
StartCoroutine("CoStart");
}
function CoStart() : IEnumerator
{
while(true)
{
yield CoUpdate();
}
}
function CoUpdate()
{
//I have placed the code of the Update().
//And called the wait function wherever needed.
}
function wait()
{
checkOnce=1; //Whenever the character is moved.
yield WaitForSeconds(2); //Delay of 2 seconds.
}
I have to move an object when a third person controller(which is another object) moves out of a boundary. I have included "yield" in my code. But, the problem happening is: The object which was moving when I gave the code for in the Update(), is moving, but isn't stopping. And it is moving up and down. I don't know what is happening! Can someone help? Please, thanks.
I am not entirely clear what you are trying to accomplish, but I can show you how to set up a Time Delay for a coroutine. For this example lets work with a simple cool down, much like you set up in your example. Assuming you want to continuously do something every 2 seconds while your game is running a slight modification can be made to your code.
function Start()
{
StartCoroutine(CoStart);
}
function CoStart() : IEnumerator
{
while(true)
{
//.. place your logic here
// function will sleep for two seconds before starting this loop again
yield WaitForSeconds(2);
}
}
You can also calculate a wait time using some other logic
function Start()
{
StartCoroutine(CoStart);
}
function CoStart() : IEnumerator
{
while(true)
{
//.. place your logic here
// function will sleep for two seconds before starting this loop again
yield WaitForSeconds(CalculateWait());
}
}
function CalculateWait() : float
{
// use some logic here to determine the amount of time to wait for the
// next CoStart cycle to start
return someFloat;
}
If I have missed the mark entirely then please update the question with a more detail about what you are attempting to accomplish.
I am not 100% sure that I understand you question but if you want to start one object to move when the other is out of bound then just make a reference in the first object to the second object and when the first object is out of bounds (check for this in Update of the first object) call some public function StartMove on the second object.
I wouldn't suggest CoRoutines. It can sometimes crash your computer. Just define a variable and decrement it. Example:
private float seconds = 5;
then do anywhere you want to delay:
seconds -= 1 * Time.deltaTime;
if(seconds <= 0) {your code to run}
This will make a delay of 5 seconds. You can change 5 to any value to change the number of seconds. Also you can speed up the decrement by changing the value of 1. (This is mostly useful when you want to sync 2 delayed actions, by using the same variable)
Hope this helps. Happy coding :)

How to pause a loop to ask for input (iPhone)

I have a fairly simple looped operation that checks for obvious errors and likely problems in a data structure. I won't go into detail about it. What I want to be able to do is pause the execution of this loop whenever an error is encountered so that I can ask the user what they want to do about that error, before continuing to check the remaining data.
Can anyone give any ideas about how best to do that?
-Ash
This will stop your loop for 0.25 seconds, but it's not what you are looking to do. You need to reformulate your question first.
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false);
Don't do long operations inside a loop in the UI run loop. It presents a non-responsive UI to the user; and the OS may kill the app if it locks up for too long.
Break the loop into short callbacks (make the inside of each loop iteration a method), and exit each callback after maybe a fraction of a seconds worth of inner loop operations.
Or execute the loop as a task in a background thread, and use locks to stop the loop while waiting for messages from the foreground UI run loop about what to do for some loop state.
Seems like UIAlertView is what you are looking for:
UIAlertView Class Reference
UIAlertView is asynch, so it won't pause the loop.
There are cleverer ways to write your loop, e.g. using blocks or completion handlers, but I'd suggest the EASIEST way is simply convert your code from:
-(void) method
{
...
for( int i=0; i<10; i++)
{
check_loop_item(i);
}
}
to:
int iCurrent, iEnd;
-(void) method
{
...
iCurrent = 0;
iEnd = 10;
[self doLoop];
}
-(void) doLoop
{
if( iCurrent >= iEnd )
return;
check_loop_item(iCurrent);
...
if( error )
{
// Popup a UIAlertView
}
else
{
iCurrent++;
[self doLoop];
}
...and in the callback method from UIAlertView, do:
-(void) callbackFromUIAlertView
{
iCurrent++;
[self doLoop];
}
...i.e. a loop that runs once at a time, and lets you arbitrarily stop / pause / resume it.