iPhone - core motion timestamp - iphone

I am using core motion on my app. I have the motionManager object assigned to a property on my main class. Something like
#property (nonatomic, retain) CMMotionManager *motionManager;
every time I will use core motion, I assign it using something like:
- (void) initializeCoreMotion {
CMMotionManager *myMotionManager = [[CMMotionManager alloc] init];
self.motionManager = myMotionManager;
[myMotionManager release];
}
Then, on the method that samples that data, I have this to read the timestamp of a sample.
CMDeviceMotion *motion = self.motionManager.deviceMotion;
timestamp = motion.timestamp;
if (firstTime) {
timestampReference = timestamp;
firstTime = NO;
} else {
timestamp = timestamp - timestampReference;
}
That is: the first time it samples, it stores the initial value. The subsequent times it samples, it will subtract the current value from the reference to know how many seconds passed.
the problem is this. Suppose I am sampling one time per second. I first sample for 10 seconds. So timestamp variable will go like 0, 1, 2, 3, 4, 5...10. Then I stop and do not sample for 20 seconds. When I start sampling again. The second time, timestamp will start at 31, 32, 33, 34...
I have checked the sampling method and firstTime is YES every time a first sample occurs...
any thoughts? How do I reset that?
thanks.

Seems to be fine the way you do it. But why do you create a new instance of CMMotionManager? I use:
if ([motionManager isDeviceMotionAvailable] && [motionManager isDeviceMotionActive]) {
[motionManager stopDeviceMotionUpdates];
}
and to continue:
[motionManager startDeviceMotionUpdatesToQueue:operationQueue withHandler:deviceMotionHandler];
I was curious to see if there is still something wrong in iOS with the timestamps and thus I just tried out your code or similar thing using a static. Everything works as expected. Maybe your timestampReference is overwritten somewhere else?

Related

Checking for a Day Change - Timezone Adjusted

I just took a stab at creating some code (pasted below) that would check for a day change. However, now I'm reading that there's a special function for day changes.
NSCalendarDayChangedNotification
Apparently it works in iOS8 and later. But people keep using the phrase "you can listen to it"... as if using that function is like tuning into a radio station. I looked it up and the last WWDC provided a presentation with some relevant code:
Reacting to the Change of Day • You may want to run some code when the
day changes NSCalendarDayChangedNotification • Example
noteCenter = [NSNotificationCenter defaultCenter];
observer = [noteCenter addObserverForName:NSCalendarDayChangedNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
// your code here
}];
My Question
The PDF I found doesn't say much else though. So my question is how does this function work? The PDF makes it seem like it truly is just this simple, paste that code in and I'm done. Is that true? Will it adjust for timezones? Do I have to enable this notification center that it is referencing?
My code (not sure if it would work):
//Find out if it's a new day
let lastDateUsed_NSDefault = NSUserDefaults.standardUserDefaults()
if let endOf_LastDateUsed = lastDateUsed_NSDefault.objectForKey("lastDateUsed") as! NSDate! {
print("Success! NSUserDefault key: 'lastDateUsed' returned \(endOf_LastDateUsed)")
//Check if the day has changed
let calendar = NSCalendar.currentCalendar()
let startOfToday = calendar.startOfDayForDate(now)
if endOf_LastDateUsed.compare(startOfToday) == NSComparisonResult.OrderedAscending {
//endOf_LastDateUsed is greater than startOfToday.
print("Do nothing! Last date used must have been today!")
} else if endOf_LastDateUsed.compare(startOfToday) == NSComparisonResult.OrderedAscending {
//Day has changed. Run alert.
//Save "endOfToday" date value to NSDefault
let endOfToday = startOfToday.dateByAddingTimeInterval(24 * 60 * 60)
NSUserDefaults.standardUserDefaults().setObject(endOfToday, forKey:"lastDateUsed")
print("Time stored in NSDefault: \(endOfToday)")
}
}
else {
print("Failure! NSUserDefault key: 'lasteDateUsed' returned nothing. No record.")
//First time user - Set end of today
let calendar = NSCalendar.currentCalendar()
let startOfToday = calendar.startOfDayForDate(now)
print("startOfToday: \(startOfToday)")
let endOfToday = startOfToday.dateByAddingTimeInterval(24 * 60 * 60)
//Store
NSUserDefaults.standardUserDefaults().setObject(endOfToday, forKey:"lastDateUsed")
print("Time stored in NSDefault: \(endOfToday)")
}
The documentation (which was slightly harder to locate than I'd have hoped, admittedly) is reasonably clear:
Posted whenever the calendar day of the system changes, as determined by the system calendar, locale, and time zone.
So yes, it should handle daylight saving changes appropriately, given that it knows about the time zone. I don't know about enabling the notification centre, but that should be easy enough to test by adjusting the system clock or time zone on a device and seeing what happens.
(What isn't clear from the docs is whether this event is fired if the date is changed via manual intervention, e.g. through changing the system time or time zone in a way that directly changes the date. It would be worth you experimenting with that.)

How can I control UISlider Value Changed-events frequency?

I'm writing an iPhone app that is using two uisliders to control values that are sent using coreBluetooth. If I move the sliders quickly one value freezes at the receiver, presumably because the Value Changed events trigger so often that the write-commands stack up and eventually get thrown away. How can I make sure the events don't trigger too often?
Edit:
Here is a clarification of the problem; the bluetooth connection sends commands every 105ms. If the user generates a bunch of events during that time they seem to que up. I would like to throw away any values generated between the connection events and just send one every 105ms.
This is basically what I'm doing right now:
-(IBAction) sliderChanged:(UISlider *)sender{
static int8_t value = 0;
int8_t new_value = (int8_t)sender.value;
if ( new_value > value + threshold || new_value < value - threshold ) {
value = new_value;
[btDevice writeValue:value];
}
}
What I'm asking is how to implement something like
-(IBAction) sliderChanged:(UISlider *)sender{
static int8_t value = 0;
if (105msHasPassed) {
int8_t new_value = (int8_t)sender.value;
if ( new_value > value + threshold || new_value < value - threshold ) {
value = new_value;
[btDevice writeValue:value];
}
}
}
I guess that it does make sense to still triggered them... What I would do in your case, would be to check the delta between the current value and the previous value. For instance:
Current value -> 5.
Next value -> 6.
Delta 1
Just a bit of pseudo-code:
if(delta>5){
//do your stuff
}
I wouldn't probably do this but:
-(void)sliderValueChanged:(UISlider *)sender{
[self performSelector:#selector(removeAction:) withObject:sender afterDelay:0.3];
// Do your stuff
}
- (void)removeAction:(UISlider *)sender{
[sender removeTarget:self action:#selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self performSelector:#selector(addAction:) withObject:sender afterDelay:0.3];
}
- (void)addAction:(UISlider *)sender{
[mySlider addTarget:self action:#selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
}
I didn't tested this, but I think you get the idea.
You could get complicated and filter the input from the slider based on either some timestamp or whether the difference between the new value and the old value is greater than some threshold.
A simpler way would be to just use a different event: touchEnded. That way you are only sending a final value and not all the intermediate values.
May not be appropriate for your app but it is not entirely clear what you are needing to do.
Just an idea, but what you could do is not send in the value changed event. You could store the value of the last transmission in a variable, then you could have a timer running in the background that checks if the last value sent is different to the current slider value, if it is then send the new value. The timer could be set to fire every 105ms and it will only send value every 105ms if the new value is different to the last sent value.

Why does this code give EXC_BAD_ACCESS?

I am working on a game in Cocos2d for iPhone.
In my init method I have an object (type id) declared as follows (also note bossDir is declared as 1):
bossMov = [CCMoveTo actionWithDuration:1.0f position:ccp(75*bossDir, 320-55)];
[boss runAction:bossMov];
Then in a timer method I have:
if ([bossMov isDone] == YES) {
bossDir = -bossDir;
[boss stopAllActions];
[boss runAction:bossMov];
}
It moves the boss once, but after that it gives EXC_BAD_ACCESS and points me to a line in the file "CCTimer.m" that says:
if( elapsed >= interval ) {
impMethod(target, selector, elapsed); //This line in particular.
elapsed = 0;
}
How can I fix this problem?
have you tried the NSZombieEnabled because i am not a cocos2d guy but just as a suggestion i am telling you this. Because bad access error comes only when you are pointing to an object which is no longer in the memory and the application crashes if you try to do so
You are not retaining bossMov action. So when you call [boss stopAllActions]; it is released and deallocated. Then you are trying to run the deallocated action - so you get the bad access.

iOS Development: What's a simple way to calculate the number of seconds that have passed between two events?

I need to calculate the number of seconds that have passed between two events on the iPhone. To do so, I need to store the time that the first event occurred and check it against the time the second event occurred to see if more than 30 seconds has passed.
I'm about to begin trying to accomplish this using the NSDate class, but I was wondering if there's a simpler way to do this without using objects, as I would prefer to store simple, intrinsic values instead of objects.
Thanks for your wisdom!
If you really want to avoid storing objects, you can do something like:
double startTime = [[NSDate date] timeIntervalSince1970];
//Run your other code
double endTime = [[NSDate date] timeIntervalSince1970];
if (endTime - startTime > 30) {
//30 seconds have passed
}
You can use
[NSDate dateWithTimeIntervalSinceReferenceDate:anotherDate];
or use the initWithTimeIntervalSinceReferenceDate: method
have you seen UIEvent's timestamp?
example:
double event1Timestamp, event2Timestamp; ///< ivars in your class?
{ // some function/method body
event1Timestamp = event1.timestamp;
}
{ // some other function/method body
/*** later that day ***/
event2Timestamp = event2.timestamp;
if (30 <= (event2Timestamp-event1Timestamp)) {
printf("ok, it's been 30 seconds");
}
}
where event1 and event2 are naturally the incoming events

Comparing to NSDates not working, incompatible pointer types

Hey i am trying to compare the date on which the user opens the app to the date it is currently. (basically, how long they've had the app in days)
Here is the code:
- (NSInteger) daysAfterDate: (NSDate *) aDate
{
NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; //#1
return (NSInteger) (ti / D_DAY); //#2
} //#3
-(void)load {
NSDate *birthdate = [prefs objectForKey:#"Birthdate"];
rock_Age = daysAfterDate(birthdate);
}
errors:
1.) it tells me incompatible types in initialization
2.) D_DAY Undecared
warning:
3.) control reaches end of non void function
If i did this completely wrong, (because for the life of me i cannot understand the NSDate class :/) I would gladly take an alternative to doing this :)
all help is appreciated,
Thank you
-Jackson Smith
The load method is correct, the following should work for -[daysAfterDate:].
#define D_DAY 86400
-(NSInteger)daysAfterDate:(NSDate *)aDate {
NSTimeInterval ti = [[NSDate date] timeIntervalSinceDate:aDate];
return (NSInteger) (ti / D_DAY);
}
1) is because self is probably no NSDate. Use [NSDate date] to get the current time/date.
2) is because you have to define D_DAY
3) only happens because of 2).
I hope this helps.
The following article might also be informative: (Ars Technica)
Does the local method timeIntervalSinceData return an "NSTimeInterval" (typdef double)? I'm guessing it doesn't, hence the error - but the code isn't here to see.
We need to see a bit more code to help you - but the D_DAY undeclared should be easy to resolve. Assuming it's not a #define somewhere in your headers, you need to specify what it is in that function or higher up in the file. I'm guessing you're just missing a #define somewhere that puts in a specific value - at least by syntax.
The warning is because of this error - the parser doesn't know how to complete things nicely until you've fixed that.
for 1) i think it talks about "self" ;it is a date?