Best way to do a massive data sync from HealthKit? - objective-c

I am looking for a smart way to import ALL data for ALL time from HealthKit in a smart way for high volume users who log certain HealthKit values hundreds of times a day for months or years. I'm also looking to do this off the main thread and in a way that is robust to the fact that users can close the app whenever they feel like. Here's what my current implementation is:
- (void) fullHealthKitSyncFromEarliestDate {
dispatch_queue_t serialQueue = dispatch_queue_create("com.blah.queue", DISPATCH_QUEUE_SERIAL);
NSLog(#"fullHealthKitSyncFromEarliestDate");
NSDate *latestDate = [PFUser currentUser][#"earliestHKDate"];
if (!latestDate) latestDate = [NSDate date];
NSDate *earliestDate = [healthStore earliestPermittedSampleDate];
NSLog(#"earliest date %# and latest date %#", earliestDate, latestDate);
if ([earliestDate earlierDate:[[NSDate date] dateByAddingYears:-2]] == earliestDate) {
earliestDate = [[NSDate date] dateByAddingYears:-1];
}
__block NSDate *laterDate = latestDate;
__block NSDate *earlierDate = [latestDate dateByAddingMonths:-1];
int i = 0;
while ([earlierDate earlierDate:earliestDate] == earliestDate) {
// DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(i * 30 * NSEC_PER_SEC)), serialQueue, ^{
NSLog(#"calling sync from %# to %#", earlierDate, laterDate);
[self syncfromDate: earlierDate toDate:laterDate];
laterDate = [laterDate dateByAddingMonths:-1];
earlierDate = [laterDate dateByAddingMonths:-1];
earlierDate = [[earliestDate dateByAddingSeconds:1] laterDate:earlierDate];
});
}
}
I am having a few problems with the above code:
earlierDate is sometimes not getting updated for the next iteration. It's like there's some weird overlap that sometimes the same date range gets called twice or even more times.
Kernel memory allocation issues (as I retrieve objects I queue them for upload to a remote server)
Interface stops responding entirely even though this is all happening off the main queue. There may be something way down stream that gets called at the end of the entire query...but I'm still surprised the interface basically stops responding altogether. It usually does fine with similar syncing for short time periods. And here I'm just doing a month at a time in queries spaced 30 seconds apart
I realize without the details of additional code this may be too murky to address, but can people tell me what sort of solutions you have implemented for cases where you want to retrieve massive amounts of data from HealthKit. I realize I may get responses like 'that's what HealthKit is for...why are you duplicating all that data?'. Suffice it to say it's required and there's no way around it.
Also, am I just misunderstanding entirely how to use a serial queue?
Ideally I'd like to do the following: (1) Run only one query at a time in this for loop (2) and run them with some reasonable period of time between them, say 30 seconds apart, because at the end of each query I do need to do some interface updates on the main qeue (3) do all the queries on a background loop in such a way that it's not degrading interface performance and can be killed at any time the user decides he's gonna kill the app. That's what I thought I would achieve with the above...if folks can tell me where my threading is going wrong I'd really appreciate it. Thanks!

Related

Changing Philips Hue Brightness with a UISlider Objective C

I am building an app that controls three philips hue RGB LED bulbs. I want to be able to change the brightness using the UISlider. Currently I have a UISlider that calls a method upon each change, however, this method far exceeds the philips hue bridge's 10 commands per second limitation. Here is the method I call upon a change in the UI slider.
- (void) changeBulbBrightness: (NSNumber *)currentBrightness
{
NSTimeInterval timeInterval = [self.timeLastCommandSent timeIntervalSinceNow];
NSLog(#"Time Since Last command: %f", timeInterval);
if (timeInterval < -0.3)
{
NSLog(#"COMMAND SENT!!!!");
PHBridgeResourcesCache *cache = [PHBridgeResourcesReader readBridgeResourcesCache];
PHBridgeSendAPI *bridgeSendAPI = [[PHBridgeSendAPI alloc] init];
for (PHLight *light in cache.lights.allValues)
{
PHLightState *lightState = light.lightState;
//PHLightState *lightState = [[PHLightState alloc] init];
if (lightState.on)
{
[lightState setBrightness:currentBrightness];
// Send lightstate to light
[bridgeSendAPI updateLightStateForId:light.identifier withLightState:lightState completionHandler:^(NSArray *errors) {
/*if (errors != nil) {
NSString *message = [NSString stringWithFormat:#"%#: %#", NSLocalizedString(#"Errors", #""), errors != nil ? errors : NSLocalizedString(#"none", #"")];
if (self.loggingOn)
{
NSLog(#"Brightness Change Response: %#",message);
}
}
*/
}];
}
self.timeLastCommandSent = [[NSDate alloc]init];
}
}
self.appDelegate.currentSetup.brightnessSetting = currentBrightness;
NSLog(#"Brightness Now = %#", currentBrightness);
I've tried making a timer to limit the amount of commands to 10 per second but the bridge still acts the same way it does when it is overwhelmed with commands (stops acceptance of all commands). Any help or direction would be greatly appreciated. Thanks in advance!
One reason might be your multiple lights. You are sending an update command for each light. So if you have 3 bulbs connected as in the Hue starter kit, you might still send 10 or a little more if there is some unfortunate caching involved packing the updates from 2 seconds into 1 second of sending. Thus I suggest you further decrease the number of updates you are sending (try 0.5 or even 1.0) as an interval and see if it gets better.
Also note that the SDK is quite vague about the rate limit. It says:
If you stay roughly around 10 commands per second
Since the Philips Hue SDK is generally not that well supported (look at the open GitHub issues), take this with a grain of salt and do your own experiments. Once I have the time to check it myself, I will post an update here.
Update 1: I just discovered this remark by one of the contributors to the Hue SDK github repo (maybe Philips employee) advising to only send 2 commands per second:
As mentioned earlier, be careful when doing lot's of requests in a loop as the calls to PHBridgeSendAPI are not blocking and requests are retained until they get a response or timeout. Two calls per second seems like a safe rate, if you want to have a higher rate, it's advised to chain requests with a queuing mechanism of your own (to ensure memory will be released before new requests are getting called).

Working with time intervals in data logging?

I'm programming a data logging application. I need to be able to store a time interval typed in by the user using Core Data. For instance, if the user completes a task in seven minutes and twenty-three seconds, he/she can type 7:28 into the NSTextField and that will be part of the data.
What class should I use to store the time? NSDate seems to be the right way of doing it, but it does not seem to store time intervals. I see that there is an NSTimeInterval class. However, with no particular reference for it, I do not know how to use it.
Also, when this time interval is stored in objects within Core Data, I need to be able to retrieve those items and sort them (using NSSortDescriptor); in order to retrieve the entry that logged the lowest time interval. This is just additional information to help figure out what I need to do here.
From the docs: NSDate objects represent a single point in time.
From your use case it sounds like you want the user to log a relative time, and then to be able to sort by which is the smallest. In that case, NSDate is not a good option. The best solution is to just store the time interval as an NSUInteger, where the integer represents your value in seconds, and then do the appropriate conversions on either end.
If the user types in 7:28, could you convert this into seconds (448 seconds) and store it in a NSUInteger? That would make sorting it easily because you would not have to deal with separate minute and second values.
Here's what I think you should do:
Have two fields for user input: one for minutes and one for seconds.
Have some code like this:
NSInteger totalTime1 = 0;
totalTime += [minuteField.text integerValue]*60;
totalTime += [secondField.text integerValue];
Now store totalTime1 using Core Data. To retrieve the times and sort them, do something like this:
//Retrive times
NSArray *retrievedTimes = [NSArray arrayWithObjects: time1FromCoreDataAsNSNumber, time2FromCoreDataAsNSNumber, etc, nil];
NSArray *sortedRetrievedTimes = [retrievedTimes sortedArrayUsingSelector:#selector(compare:)];
//Now the array is sorted from lowest to highest
NSInteger lowestValue = [[sortedRetrievedTimes objectAtIndex:0] integerValue];
Hope this helps!

Guarantee Order in NSURLConnection

Let me start off with some code. When the application loads, it calls the following:
//Creates custom URL for request, loads the request, and upon completion (as per the delegate response, it runs the selector)
//List of programs
URLCreator * getListURL = [[URLCreator alloc] initStandard:#"getList"];
WebManager *getListWM = [[WebManager alloc]init];
[getListWM load:[getListURL finalURL] withSelector:#selector(createProgramList)];
//Sorting order for program list
URLCreator * getSortURL = [[URLCreator alloc] initStandard:#"getSort"];
WebManager *getSortWM = [[WebManager alloc]init];
[getSortWM load:[getSortURL finalURL] withSelector:#selector(sortThroughPrograms)];
This code so far works well except for one thing - my responses come out of order. This is to be expected because the list of programs is much larger than the sorting order. Basically, what needs to happen is I need to guarantee I have the list of programs AND the sorting order before I can perform any type of sorting algorithm.
Without locking up the program by doing a synchronous request, what is the best way to guarantee that I have BOTH before performing the sorting algorithm? Sure, I can set BOOL flags, but I would need to constantly check to see when both have been received.
You could use NSOperationQueue for this.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html

problem with saving data at coredata?

In my application there is searchBar. when we input a text, it will do functionGrab (grab data from internet and save it to coredata), example :
if we input "Hallo"
if([[dict objectForKey:#"Category"] isNotEmpty] && [[[dict objectForKey:#"Category"] objectAtIndex:0] class]!=[NSNull class]){
NSMutableArray * DownloadedTags =[dict objectForKey:#"Category"];
NSMutableSet * TagsReturn=[NSMutableSet set];
for(int i=0;i<[DownloadedTags count];i++){
NSString * Value=[DownloadedTags objectAtIndex:i];
Tag * thisTag= (Tag*)[GrabClass getObjectWithStringOfValue:Value fromTable:#"Tag" withAttribut:#"Name"];
[TagsReturn addObject:thisTag];
}
NSMutableSet * manyManagedObjects = [BusinessToSave mutableSetValueForKey:#"Tags"];
[self removeDifferenceBetween2MutableManagedObjectSets:manyManagedObjects withDownloadedVersion:TagsReturn];
}
So each biz has many categories. WHat happen in multi threaded application is one thread put category. The other thread also put the same category before committing.
So, [GrabClass getObjectWithStringOfValue:Value fromTable:#"Tag" withAttribut:#"Name"]; gives a new object even though some other thread already created the same object without knowing it.
If I synchronized the whole thing that the code would run serially and that'll be slow.
functionGrab:"H"
functionGrab:"Ha"
functionGrab:"Hal"
functionGrab:"Hall"
functionGrab:"Hallo"
something like,it do that functionGrab 5 times
I want to make functionGrab at background, but the problem is when I do that function without synchronized it will save more than one of data, so the result is there are 5 hallo words in my coredata, but if I do that with synchronized, it spent so much time, so slow..
is there any way to help my problem?
I do not recommended having more than one thread "creating" the same types of data for the exact reason you are running into.
I would suggest you queue all of your "creates" into a single thread and a single NSManagedObjectContext to avoid merge or duplication issues.
The other option would be to make the app Lion only and use the parent/child NSManagedObjectContext design and then your children will be more "aware" of each other.

Pauses/computation between function execution?

I'm working on a game and the speed of the game is 60fps, giving me about 16ms to execute what I need to execute. What I'm finding tho is that certain code paths are taking a while to execute. At first I thought this must be an issue with memory allocation/deallocation. It could possibly be, but I have implemented object pooling for the more heavyweight objects, and this seems to have had little effect.
I have stripped out the offendingly large objects, and replaced them with a much simpler object, yet it still takes about 3ms to make this object. The simple object consists of two custom objects, 2 arrays, and 2 dictionaries. The large object is of an arbitrary complexity. Making the more complex larger objects seem to take linearly more time, taking up to 20-30ms. In many instances in my game I can make a much more complicated object in a fraction of the time. But somehow these specific locations in code cause a serious slowdown.
I am using the following code to profile my functions (from SO originally):
NSDate* methodStart = [NSDate date];
// My code here.
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"[CH] executionTime to create %# = %f", myObject , executionTime );
As best as I can confirm if I do something like the above in an inner and outer function, it looks like there can be a serious slowdown:
Inner function call completed: 4ms
...no code between inner and outer code except timer...
Outer function call completed: 8ms
My current theory is there is 'in-between' computation that occurs between the functions that is causing the serious slowdowns. As I'm new to Obj-C/C I'm not entirely sure what this slowdown could be. It could be threading, it could be because of memory alloc/autorelease/dealloc, or some other kind of unrelated issue. I have attempted to get more info from Instruments with little benefit.
So my question is: Does this sound logical? Is it possible that some kind of computation could be happening between my functions that would take up 2-4ms of cpu on an ipad2? And if my theory isn't possible, any ideas what it could be?
The best way to track down this type of problem is to use Instruments to profile the execution of the code. Often, you can run this against the code on the Mac under the simulator to see where the time is going, however, in this case you may need to profile it on your iPad to be certain.
Remove your NSDate-based profiling code, as NSDate can be a pretty heavy-weight object, especially when you put the results into the autorelease pool, which you are doing here.
If you feel you must do NSDate-based profiling, you should only need to create a single NSDate object and the use:
[methodStart timeIntervalSinceNow]
to calculate the time delta without having to create a separate object and perform a date subtraction operation.