My Objective C app on iOS 7 gets location updates in the background from either the startUpdatingsignificantLocationChanges or startUpdatingLocation delegate (which one depends on the mode that the app is in, but I don't think it matters).
In the delegate, I gather the location info, write it to a dictionary, and then write the dictionary to a Firebase.
// this code is in the location update delegate routine
// the code that gathers the various elements that go into the dictionary
// are omitted for clarity, I don't think that they matter
// we may be running in the background on iOS 7 when we are called!
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[[NSNumber numberWithFloat:newLocation.coordinate.latitude] stringValue], #"Latitude",
[[NSNumber numberWithFloat:newLocation.coordinate.longitude] stringValue], #"Longitude",
[[NSNumber numberWithFloat:newLocation.horizontalAccuracy] stringValue], #"Accuracy",
formattedDateString, #"TimeNow",
[dateFormatter stringFromDate:newLocation.timestamp], #"TimeStamp",
[[NSNumber numberWithDouble:interval] stringValue], #"Date",
self.mode, #"Mode",
nil];
// Write it once to CurrentLocation
[ref setValue:dictionary];
// yes, I know this is clumsy
fbTmp = [NSMutableString stringWithString: fbRoot];
[fbTmp appendString : #"/locationHistory"];
ref = [[Firebase alloc] initWithUrl:fbTmp];
// Now write it again to the locationHistory list
ref = [ref childByAutoId];
[ref setValue:dictionary];
Sometimes it works, sometimes it doesn't (i.e. in the same run of the app, sometimes the location gets written to the Firebase successfully as expected, and sometimes it doesn't. There isn't any obvious rhyme or reason to when it seems to work and when it doesn't).
I suspect that the issue is that the Firebase write is not completing successfully in background mode, but I'm not sure. I am very new to iOS and Objective C and Firebase.
My app is marked in its Capabilities as requiring background services for Location updates and Background fetch (the latter my random attempt to fix this problem, the former I know that I need).
My suspicion is that I need to tell the OS that I need time to complete the write with a backkgroundTask, and then terminate the background task in the completion block of the firebase write - has anyone verified that that will work when running in background mode?
If so, do I just need to do that in the second write (assuming that they are completed in order), or in both (with a counter that I count down as each write completes)?
Any hints most appreciated.
Yes, you need to finish your task in background. It says so in the Apple Documentation:
If your app is in the middle of a task and needs a little extra time to complete that task, it can call the beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: method of the UIApplication object to request some additional execution time. Calling either of these methods delays the suspension of your app temporarily, giving it a little extra time to finish its work. Upon completion of that work, your app must call the endBackgroundTask: method to let the system know that it is finished and can be suspended.
Just put your code in a background task, give it maximum time (3 minutes I think).
Read up on Apple app lifecycle and everything should clear up for you for future reference.
Related
I'm trying to do a pretty basic thing: set up an HKObserverQuery so I can know when various data points are changed (I've made sure that the user has authorized the app to use the data point in question.) For whatever reason, I can get the query to fire every time the app is launched, but it does not fire when I close the app, go into the Health app, and manually update the data point. I've done a fair amount of searching and haven't been able to successfully use the code that others have posted, code that they say works for them.
I'm two weeks into Cocoa/Objective C development, so I'm sure I'm missing something obvious, but I can't see what it is. Any guidance here would be great, even if it's just advice on debugging. Since the app itself is closed and I'm not getting anything that it might log out in the console, I don't really have any visibility into what's happening.
The code that I'm using for the observer query is below:
HKQuantityType *heartRate = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
[self.healthStore enableBackgroundDeliveryForType:heartRate frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"observing heart rate");
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.bodbot.com/Scripts/wearable_heartrate_changed.php"]];
}else{
NSLog(#"FAILED observing heart rate");
}
}];
HKObserverQuery *query = [[HKObserverQuery alloc] initWithSampleType:heartRate predicate:nil updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.bodbot.com/Scripts/wearable_heartrate_changed.php"]];
}];
[self.healthStore executeQuery:query];
Thanks!
I have found, empirically (not from documentation), that the Observer Query does NOT fire when running in the simulator but it DOES fire when running on device. And I do not have the background modes capability turned on.
When you suspend an app on iOS, by default it stops running unless it has taken a background task assertion or has a background mode entitlement. The app cannot receive notifications when it is not running. HealthKit has a feature which can wake your app in the background when there are new samples of a particular type, though. See the Managing Background Delivery documentation for HKHealthStore. Use that in conjunction with HKObserverQuery to be notified whenever there is new data, even when your app is not already running.
I have a view with a bunch of UISwitch.
My problem is that when I tap on a switch I need to wait about 10 seconds before being able to tap any other switch of the view.
Here is my code :
-(void) didTapSwitch:(UISwitch *)sender
{
NSLog(#"BEGIN didTapSwitch, %#",sender);
DADudesManager *dudesManager = [DADudesManager getInstance];
DADude *updatedDude = [dudesManager.dudesList objectAtIndex:[[self.spendingDudesTableView indexPathForCell:sender.superview.superview] row]];
DAAccountManager *accountManager = [DAAccountManager getInstance];
[accountManager.accountsOperationQueue addOperationWithBlock:^{
NSLog(#"BACKGROUND OPERATION BEGINS switchDudeBeneficiates, %#",sender);
DASpendingsManager *spendingsManager = [DASpendingsManager getInstance];
[[spendingsManager.spendingObserver childByAppendingPath:self.spending.spendingID] updateChildValues:#{updatedDude.dudeName: [sender isOn] ? #"1" : #"0"}];
NSLog(#"BACKGROUND OPERATION ENDS switchDudeBeneficiates, %#",sender);
}];
NSLog(#"END switchDudeBeneficiates, %#",sender);
}
My spendingObserver is a Firebase object initiated before.
When the code above is executed, the NSLogs show almost instantaneously in the console, the data is updated online at the same time, but the switches don't react to any tap for another 9 to 11 secs.
Of course commenting the line [[spendingsManager.spendingObserver childByAppendingPath:self.spending.spendingID] updateChildValues:#{weakDude.dudeName: [weakSwitch isOn] ? #"1" : #"0"}]; removes the latency, so the problem must come from Firebase, but I have no clue what's going on.
I am probably missing something obvious as I'm pretty new to IOS development !
I can think couple of reasons.
You are sending the PayLoad in the main thread, which is causing the User INterface events to be suspended.
The code you ran, might be linked to other functions in the library you are using, that might be causing the lag.
TRY - >
try putting your code in an NSOperation and execute that. Or use GCD to do work on different thread just not the UI thread which is the main thead.
Step back and simplify. Make your switch code simply log the change in value. NSLog includes a timestamp, so you can tell when the switch events occur.
If do-nothing code responds quickly, as I suspect it will, then add log statements at the beginning and end of your switch action method. That way you can see if there is a delay between the beginning and end of the processing.
You could also run the app in instruments (time profiler) and see where your app is spending time.
I want to store some of my application data in iCloud, and I want it to be saved when the application is going to the background or is shut down.
I have a MyDocument class, which is written in accordance with this Apple tutorial. In fact, I do this:
// this function called from applicationDidEnterBackground
void SaveICloudData( const char *rawData )
{
MyDocument *doc = AppDelegate.getICloudDocument; // MyDocument is subclass of UIDocument, like in tutorial
NSString *str = [[NSString alloc] initWithUTF8String:rawData];
[doc setDocumentText:str];
}
My app goes to the background and is synchronized only when I turn it on again. But I want to synchronize my data with iCloud manually. How can I do this?
Before exiting, UIDocument checks if the document hasUnsavedChanges. If YES, saving is invoked.
You are setting the document text in the applicationDidEnterBackground delegate method, which is probably too late.
From the method docs:
You should perform any tasks relating to adjusting your user interface
before this method exits but other tasks (such as saving state) should
be moved to a concurrent dispatch queue or secondary thread as needed.
Because it's likely any background tasks you start in
applicationDidEnterBackground: will not run until after that method
exits, you should request additional background execution time before
starting those tasks. In other words, first call
beginBackgroundTaskWithExpirationHandler: and then run the task on a
dispatch queue or secondary thread.
This is my problem, I'm building an iOS with some JSON returs from my server, here, no problems, all works fine.
The problem is that when I run the program, it take a long long time to parse the result into a NSMutableArray: this is the log
2013-01-10 12:03:48.627 project[5917:907] <- time begin parser
2013-01-10 12:03:48.755 project[5917:907] <- time finish parser
2013-01-10 12:03:48.756 project[5917:907] <- time begin implement arrays
2013-01-10 12:03:58.522 project[5917:907] <- time finish implement array
As you can see, implementing the arrays is really long.
I know that I have to use queueing and grand central dispatch to make my UI responsive, but I don't know how to, could you please help me to do that ?
This is my viewDidLoad Method
- (void)viewDidLoad
{
[super viewDidLoad];
if debug
NSLog(#"<- time begin parser");
endif
NSString *URLStr = #"http://myJsonFile.json";
NSDictionary *myDictwithReturn = [TOCJSONParser awesomeParserWithStringOfYourJSONFile:URLStr]; //really cool parser, i can put it on gitHub if you want
NSArray *speakersArray = [myDictwithReturn objectForKey:#"speakers"];
myArray = [[NSMutableArray alloc]init];
NSLog(#"<- time finish parser");
NSLog(#"<- time begin implement arrays");
for (NSDictionary *myDict in speakersArray) {
_nextSpeaker = [[TOCSpk alloc]init];
[_nextSpeaker setName:[myDict objectForKey:#"name"]];
[_nextSpeaker setBusiness:[myDict objectForKey:#"business"]];
[_nextSpeaker setDesc:[myDict objectForKey:#"desc"]];
[_nextSpeaker setTwitter:[NSURL URLWithString:[myDict objectForKey:#"twitter"]]];
[_nextSpeaker setPicture:[_nextSpeaker retrieveImageFromServer:[myDict objectForKey:#"picture"]]];
[myArray addObject:_nextSpeaker];
}
NSLog(#"<- time finish implement array");
}
I suspect that the slowness comes from calling retrieveImageFromServer, which lets me think that you are accessing the network. If that access is synchronous, as it seems from the fact that you are assigning the image in the same statement, than this is bound to be slow.
You should review your code and make it run on a separate thread or use asynchronous network access.
EDIT:
After your comment about using, dataWithContentsOfURL, my above hypothesis is confirmed.
You can read this S.O. post about a way to download images asynchronously, or you might use any of various networking frameworks available out there.
Possibly, the easiest path forward is using SDWebImage, which is a class that offers async download for images, so you donĀ“t have to bother yourself with thread management or NSURLConnection:
Just #import the UIImageView+WebCache.h header, and call the setImageWithURL:placeholderImage: method from the tableView:cellForRowAtIndexPath: UITableViewDataSource method. Everything will be handled for you, from async downloads to caching management.
My CoreMIDI connection on iOS is apparently fast enough to handle ANYTHING that hits it... if I'm just doing some simple object creation and NSLog. In the UI, I don't have time to handle everything that comes in. The UI would blow up, or just finish processing too late.
However, I need to do real processing and UI display in response to CoreMIDI inputs. What I'd like is to process the latest messages every, say, 1ms or 2ms. I've been doing this with a collection that gets emptied by a timer-fired method every 1ms (processFromServerAsync). One problem is that some messages might fall through the cracks, I think, if I grab and substitute:
NSDictionary *queueCopy = [self.queue copy];
// here the dictionary could get messages not in the queue copy!
self.queue = [NSMutableDictionary dictionary];
I realize that I could handle this by synchronizing with a lock, which is easy to screw up:
-(NSMutableDictionary *)messageQueue {
#synchronized(self) {
if (!messageQueue_)
self.messageQueue = [NSMutableDictionary dictionary];
return messageQueue_;
}
}
-(NSDictionary*)clearMessageQueueAndReturnCopy {
#synchronized(self) {
if (!messageQueue_)
return [NSDictionary dictionary];
NSDictionary *retVal = [messageQueue_ copy];
self.messageQueue = [NSMutableDictionary dictionary];
return retVal;
}
}
However, I'm not convinced that I'm even handling this in the correct way. How is throttling typically done (even outside of Obj-C)? I surely cannot process all those messages in the UI nor the program.
There are some well-established patterns for throttling streams of incoming data. This comes up a lot in finance, where you might have a data feed throwing 100K messages/sec at a system.
You employ a sliding window mechanism to discard redundant messages while ensuring that the client has the latest possible copy of the data. You set your window up over some time period (a few milliseconds) then set up a queue for each data stream (meaning a particular CC, midi note etc.) You start a global timer when the first message comes in. You send that message to the client immediately. If anything else comes in during the window you push it to its queue. The queue has just one entry - the latest value - so you overwrite the queued value with each subsequent update. When the timer ticks (the window is over) you send the latest message out to the client. Then, you send the next message out as soon as it comes in, start a new window and repeat. This gives a reasonable balance between swamping the client and avoiding aliasing of update intervals to the timer window. Aliasing is less of an issue with 1-2ms intervals so a cruder rigid timer approach might work for you.
The critical thing is ensuring that you have separate windows for each data stream. You can't risk overwriting or ignoring, say, a note off because a control change came in. One timer, one single-entry queue per Midi message number.