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.
Related
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];
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.
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 :)
I wish to Show progress of a long running operation(process) in UI, so that the user can understand the status of the background job. This is the way I have implemented and I feel like the code is absurd. Below is my code
dialog.run(true,false, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.beginTask("Main process", 10);
for (int i = 0; i < 10; i++) {
if (monitor.isCanceled()) return;
monitor.subTask("Status message");
sleep(1000);
// worked increases the monitor, the values are added to the existing ones
monitor.worked(1);
if(i == 3) {
sleep(3000);
callMe();//calling a long running function
}
if(i == 9) {
monitor.subTask("finishing setup..... please wait ");
sleep(2000);
}
}
monitor.done();
}
});
Note: There is a sleep method somewhere in the code
here at i == 3 an operation/function is called that takes a minimum of 5 minutes, post execution of the function the progress continues.
I don't want the progress to be stopped while executing the function(long running operation) rather progress must be shown even while executing it.
can someone show the correct programming practices in showing progress
The reason your code feels absurd is that wrapping the long-running method in a IRunnableWithProgress.run() really does not add much in itself, there is no magic.
To make the ProgressMonitorDialog (or e.g. the related Job API) work for you, you need to change "callMe()" so it takes "IProgressMonitor monitor" as a parameter, and use that to listen for cancel-requests, and use it also for reporting progress.
To say the same again, using different wording: You need to recursively add "IProgressMonitor monitor" as a parameter to all long-running method calls. All long-running operations must be build with this (IProgressMonitor) in mind if any progress is to be reported and/or you want it to be cancelable.
I wish to do a running score animation for my iphone app in xcode such that whenever I increase the score by an integer scoreAdded, the score will run up to the new score instead of being updated to the new score. I try some for loop with sleep but to no available. So I'm wondering if there's any way of doing it. Thank you.
Add a timer that will call a specific method every so often, like this:
NSTimer *tUpdate;
NSTimeInterval tiCallRate = 1.0 / 15.0;
tUpdate = [NSTimer scheduledTimerWithTimeInterval:tiCallRate
target:self
selector:#selector(updateScore:)
userInfo:nil
repeats:YES];
This will call your updateScore method 15 times a second
Then in the main part of your game, instead of simply adding the amount to currentScore, I would instead store the additional amount in a separate member variable, say addToScore. e.g.
addToScore = 10;
Your new method updateScore would have a bit of code like this:
if (addToScore)
{
addToScore--;
currentScore++;
// Now display currentScore
}
Try redrawing the view after each iteration where your score is being displayed:
for (/* loop conditions here */) {
score += 1;
[scoreView setNeedsDisplay:YES];
}