Reputation: 18328
I am developing an iPhone app that gathers data from 3 separate feeds. In applicationDidFinishLaunching
and applicationWillEnterForeground
and Do the following:
[self emptySchedule];
[self populateSchedule];
[self emptyPlayers];
[self populatePlayers];
[self emptyNews];
[self populateNews];
The empty methods simply remove info from core data, and the populate methods add info back to core data by calling various web json/xml feeds. It seems to do this very fast; but was wondering if this is the preferred method for keeping information up to date in the app.
EDIT:
Just to give some context, here are a couple methods used for empty/populate:
Since this is mostly asynchronous will it affect application launch time?
- (void) emptySchedule
{
NSFetchRequest * allEvents = [[NSFetchRequest alloc] init];
[allEvents setEntity:[NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext]];
[allEvents setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSError * error = nil;
NSArray * events = [self.managedObjectContext executeFetchRequest:allEvents error:&error];
//error handling goes here
for (NSManagedObject * event in events) {
[self.managedObjectContext deleteObject:event];
}
NSError *saveError = nil;
[self.managedObjectContext save:&saveError];
}
-(void)populateSchedule
{
NSURL *url = [NSURL URLWithString:SCHEDULE_FEED_URL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id schedule)
{
for (NSDictionary *campEvent in schedule)
{
Event *event = nil;
event = [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
event.eventName = [campEvent valueForKeyPath:@"eventName"];
event.ticketsRequired = [campEvent valueForKeyPath:@"ticketsRequired"];
event.location = [campEvent valueForKeyPath:@"location"];
event.practiceStart = [NSDate dateWithTimeIntervalSince1970:[[campEvent valueForKeyPath:@"practiceStart"] doubleValue]];
event.practiceEnd = [NSDate dateWithTimeIntervalSince1970:[[campEvent valueForKeyPath:@"practiceEnd"] doubleValue]];
}
NSError *saveError = nil;
//Save inserts
[self.managedObjectContext save:&saveError];
//Notify other objects of this
[[NSNotificationCenter defaultCenter] postNotificationName:@"populateSchedule" object:nil];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:@"Error Retrieving Data. Please try again later." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
}];
[operation start];
}
Upvotes: 0
Views: 575
Reputation: 33428
I'll try to answer based on my personal experience. Maybe someone else could have a different opinion on it.
In your case the syncing is performed only in phases of the application lifecycle.
So, I would add a third. When the user asks it. But it strictly depends on the nature of your application. Another way could be to set up a background thread that periodically wakes up and asks the server to send it new data. This could be more complex than the manually syncing.
About these two ways I would perfom import operation in specific background threads. You could set up your own operations (NSOperation
class is there also for this type of task) and do stuff there or use new iOS 5 Queue Core Data API.
If you haven't done already (the background importing) do it also for your actual methods (I think in this case you could just unify the pairs empty
/populate
). This mechanism allows you to boost application startup and say to the user what is going on without freeze the UI:"Hello, I'm fetching data from the server! Please wait".
Edit
About the code you added it's ok for me. Only two considerations.
First, if the deletion is performed in the main thread, it could block the main thread if you have a lot of entries to remove. In this case, the UI could be not responsive. Anyway you have done a good job setting setIncludesPropertyValues
to NO
.
About the other snippet, I guess only the data download is perfomed in an asynchronous fashion. The completion handler is performed in the main thread (you can check for example with BOOL isMainThread = [NSThread isMainThread]
) and so the core data object creation and its relative saving. Also in this case if you have a lot of data the main thread could be blocked.
Anyway, if you have done some tests and the app doesn't take too long to startup, you could just remain with your code. If you start to see some sort of latency, maybe you could do Core Data operations in backgrounds.
With no iOS 5 API the save
call could (I say could since you can save chuncks of data and not the whole one) take time to be performed (in particular when you have a lot of objects to store in your core data file). Starting form iOS 5 you could take advantage of new type of NSManagedObjectContext
(queue concurrency type) and parent-child context. Furthermore you can avoid to write the entire Core Data stack and use the UIManagedDocument
class. By means of both the save
can be performed in a concurrent queue without blocking the main thread.
Hope that helps.
Upvotes: 1