How do I implement a timer for this code? - iphone

-(void) play
{
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
[motionManager startDeviceMotionUpdates];
BOOL timeReached = NO;
while(!self.stopButtonPressed)
{
if(motionManager.deviceMotion.userAcceleration.y >= ... && motionManager.deviceMotion.userAcceleration.y <= ...)
{
//start timer
}
while(motionManager.deviceMotion.userAcceleration.y >= ... && motionManager.deviceMotion.userAcceleration.y <= ... && !timeReached)
{
if(//check timer & if timer is >=300ms)
{
timeReached = YES;
NSLog(#"acceleration on Y-axis stayed between ... & .. for at least 300ms");
}
}
}
}

It seems like you're going about this the wrong way; instead of running a clock, you should be setting accelerometerUpdateInterval to whatever you're looking for and using startAccelerometerUpdatesToQueue:withHandler: to receive the data.
From the Apple documentation:
Handing Motion Updates at Specified Intervals
To receive motion data
at specific intervals, the application calls a “start” method that
takes an operation queue (instance of NSOperationQueue) and a block
handler of a specific type for processing those updates. The motion
data is passed into the block handler. The frequency of updates is
determined by the value of an “interval” property.
Accelerometer. Set the accelerometerUpdateInterval property to specify
an update interval. Call the
startAccelerometerUpdatesToQueue:withHandler: method, passing in a
block of type CMAccelerometerHandler. Accelerometer data is passed
into the block as CMAccelerometerData objects.
Once you've set everything up, let it run. When you've received a completion notice from the block look at the data you've received.

Related

Delay 'glitch' with dispatch_after swift

Currently, i have a delay function as follows:
//Delay function from http://stackoverflow.com/questions/24034544/dispatch-after-gcd-in-swift/24318861#24318861
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
This code works for what i need, but as soon as the delay gets greater than 13 or so seconds, it seems to glitch out and stop delaying. Does anyone know a solution to this, or even while this is happening?
Here is the code in my use:
var delayTime = Double(1)
for number in self.gameOrder{
if number == 0{
delay(delayTime++){self.greenButton.highlighted = true}
self.delay(delayTime++){
self.greenButton.highlighted = false
}
}
else if number == 1{
delay(delayTime++){self.redButton.highlighted = true}
self.delay(delayTime++){
self.redButton.highlighted = false
}
}
else if number == 2{
delay(delayTime++){self.yellowButton.highlighted = true}
self.delay(delayTime++){
self.yellowButton.highlighted = false
}
}
else if number == 3{
delay(delayTime++){self.blueButton.highlighted = true}
self.delay(delayTime++){
self.blueButton.highlighted = false
}
}
println(delayTime)
}
}
}
Once delayTime gets to 13, the delay starts to play up.
Thanks!
You didn't say what platform/OS, but if on iOS, this behavior changed from iOS 7 to iOS 8. It would appear to be coalescing the timers (a power saving feature to group similar timer events together to minimize the power consumption).
The solution is to refactor the code either to use a single repeating timer or rather than scheduling all of the dispatch_after calls up front, have each dispatch_after trigger the next dispatch_after in its completion block (thus never having a bunch of dispatch_after calls pending at the same time that it might be coalesced together).
By the way, if using a repeating timer, you might want to use a dispatch source timer rather than a NSTimer, as this not only gives you the ability to specify the desired leeway, but the third parameter of dispatch_source_set_timer lets you specify a value of DISPATCH_TIMER_STRICT which:
Specifies that the system should make a best effort to strictly observe the
leeway value specified for the timer via dispatch_source_set_timer(), even
if that value is smaller than the default leeway value that would be applied
to the timer otherwise. A minimal amount of leeway will be applied to the
timer even if this flag is specified.
CAUTION: Use of this flag may override power-saving techniques employed by
the system and cause higher power consumption, so it must be used with care
and only when absolutely necessary.
In Mac OS X, this can be used to turn off "App Nap" feature (where timers will be more significantly altered in order to maximize battery life), but given the appearance of this timer coalescing in iOS, it might be a useful option here, too.

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];

Placing camera with animation

I want to know that how to place camera near and far (By increasing and decreasing value of eyeZ self.camera setEyeX:0 eyeY:0 eyeZ:1]; self.camera setEyeX:0 eyeY:0 eyeZ:180];) including animation (for smoothness), as normally it provide jerky zooming.
My suggestion is creating your own subclass of CCActionInterval, say CCCameraZoomAnimation and override its update method. The main advantage of having an action, aside from being able to control the camera movement finely, is also the possibility of using this action through CCEaseOut/CCEaseIn (etc.) to obtain nice graphical effects.
CCCameraZoomAnimation would have the node whose camera you want to modify as a target and another parameter to the constructor specifying the final Z value.
#interface CCActionEase : CCActionInterval <NSCopying>
{
CCActionInterval * other;
}
/** creates the action */
+(id) actionWithDuration:(ccTime)t finalZ:(float)finalZ;
/** initializes the action */
-(id) initWithDuration:(ccTime)t finalZ:(float)finalZ;
#end
The update method is called with an argument dt which represents the elapsed time since the start of the action and would allow you to easily calculate the current Z position:
-(void) update: (ccTime) t
{
// Get the camera's current values.
float centerX, centerY, centerZ;
float eyeX, eyeY, eyeZ;
[_target.camera centerX:&centerX centerY:&centerY centerZ:&centerZ];
[_target.camera eyeX:&eyeX eyeY:&eyeY eyeZ:&eyeZ];
eyeZ = _intialZ + _delta * t //-- just a try at modifying the camera
// Set values.
[_target.camera setCenterX:newX centerY:newY centerZ:0];
[_target.camera setEyeX:newX eyeY:newY eyeZ:eyeZ];
}
You would also need to implement copyWithZone:
-(id) copyWithZone: (NSZone*) zone
{
CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] finalZ:_finalZ];
return copy;
}
and make use of startWithTarget to
-(void) startWithTarget:(CCNode *)aTarget
{
[super startWithTarget:aTarget];
_initialZ = _target.camera....; //-- get the current value for eyeZ
_delta = ccpSub( _finalZ, _initialZ );
}
Nothing more, nothing less.
Sorry if copy/paste/modify produced some bugs, but I hope that the general idea is clear.
if you increase the 'z' by 180 from the off, you are bound to get a jerky animation, try running this in an animation context loop,increasing the value over a period of time will allow you to have a smooth 'zoom'.

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.

how to do a running score animation in iphone sdk

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];
}