Skip to content

Commit

Permalink
Fixes #12, Fixes #13: Update data in main thread only once a day
Browse files Browse the repository at this point in the history
  • Loading branch information
theandrewdavis committed Aug 18, 2013
1 parent 646e13e commit 06682dd
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 44 deletions.
12 changes: 6 additions & 6 deletions ToyLoadingScreen/ToyLoadingScreen/HGChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@

@interface HGChild : NSManagedObject

@property (nonatomic, strong) NSString* name;
@property (nonatomic, strong) NSString* biography;
@property (nonatomic, strong) NSString* gender;
@property (nonatomic, strong) NSDate* birthday;
@property (nonatomic, strong) NSString* thumbnail;
@property (nonatomic, strong) NSSet* media;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *biography;
@property (nonatomic, strong) NSString *gender;
@property (nonatomic, strong) NSDate *birthday;
@property (nonatomic, strong) NSString *thumbnail;
@property (nonatomic, strong) NSSet *media;

+ (HGChild *)addChildFromData:(NSDictionary *)data toContext:(NSManagedObjectContext *)context;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ - (void)viewDidLoad {
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self.dataController action:@selector(fetchRemoteData) forControlEvents:UIControlEventValueChanged];

// Get updates from the web and start the pull to refresh spinner.
[self.refreshControl beginRefreshing];
[self.dataController fetchRemoteData];
// If data is more than a day old, get updates from the web and start the pull to refresh spinner.
if ([self.dataController isDataStale]) {
[self.refreshControl beginRefreshing];
[self.dataController fetchRemoteData];
}
}

// Set the number of sections in the table.
Expand Down
1 change: 1 addition & 0 deletions ToyLoadingScreen/ToyLoadingScreen/HGDataController.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@

- (void)fetchLocalData;
- (void)fetchRemoteData;
- (BOOL)isDataStale;

@end
59 changes: 30 additions & 29 deletions ToyLoadingScreen/ToyLoadingScreen/HGDataController.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ - (BOOL)isNewVersion:(NSString *)version {
return ![storedVersion.value isEqualToString:version];
}

// Check if data has not been updated in one day.
- (BOOL)isDataStale {
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HGVersion class])];
NSArray *versions = [self.managedObjectContext executeFetchRequest:request error:nil];
if (versions.count == 0) {
return YES;
}
HGVersion *storedVersion = (HGVersion *)versions[0];
return [storedVersion.date timeIntervalSinceNow] < -(60 * 60 * 24);
}

// Clear all children in the store and replace them with the children in the given JSON object.
- (void)update:(NSDictionary *)data version:(NSString *)version {
// Don't update the store if the version has already been saved.
Expand All @@ -95,37 +106,27 @@ - (void)update:(NSDictionary *)data version:(NSString *)version {
return;
}

NSLog(@"Dispatching a JSON processing thread.");
// Create a background thread to store the new data in another managed object context.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
backgroundContext.parentContext = self.managedObjectContext;

// Store data from JSON into the background managed object context.
[HGVersion addVersion:version toContext:backgroundContext];
for (NSDictionary *childData in data[@"children"]) {
HGChild *child = [HGChild addChildFromData:childData toContext:backgroundContext];
NSMutableSet *media = [[NSMutableSet alloc] init];
for (NSDictionary *mediaItemData in childData[@"media"]) {
HGMediaItem *mediaItem = [HGMediaItem addMediaItemFromData:mediaItemData toContext:backgroundContext];
[media addObject:mediaItem];
}
child.media = media;
// Remove all children from the store.
[self deleteAllEntitiesOfName:NSStringFromClass([HGVersion class])];
[self deleteAllEntitiesOfName:NSStringFromClass([HGChild class])];

// Add children from the web response.
[HGVersion addVersion:version toContext:self.managedObjectContext];
for (NSDictionary *childData in data[@"children"]) {
HGChild *child = [HGChild addChildFromData:childData toContext:self.managedObjectContext];
NSMutableSet *media = [[NSMutableSet alloc] init];
for (NSDictionary *mediaItemData in childData[@"media"]) {
HGMediaItem *mediaItem = [HGMediaItem addMediaItemFromData:mediaItemData toContext:self.managedObjectContext];
[media addObject:mediaItem];
}

NSLog(@"Saving background context.");
NSError *error = nil;
if (![backgroundContext save:&error]) {
NSLog(@"Background context save failed: %@, %@", error.localizedDescription, error.userInfo);
};
child.media = media;
}

[self.managedObjectContext performBlock:^{
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(@"Main context save failed: %@, %@", error.localizedDescription, error.userInfo);
}
}];
});
// Save the context.
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(@"Context save failed: %@, %@", error.localizedDescription, error.userInfo);
};
}

@end
3 changes: 2 additions & 1 deletion ToyLoadingScreen/ToyLoadingScreen/HGManagedObjectContext.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ + (NSManagedObjectModel *)createManagedObjectModel {

// Create the version entity description.
NSAttributeDescription *versionValueDescription = [[self class] createAttributeDescription:@"value" type:NSStringAttributeType optional:NO indexed:NO];
NSAttributeDescription *versionDateDescription = [[self class] createAttributeDescription:@"date" type:NSDateAttributeType optional:NO indexed:NO];
NSEntityDescription *versionEntity = [[NSEntityDescription alloc] init];
versionEntity.name = NSStringFromClass([HGVersion class]);

Expand Down Expand Up @@ -60,7 +61,7 @@ + (NSManagedObjectModel *)createManagedObjectModel {
childMediaDescription.deleteRule = NSCascadeDeleteRule;

// Add the attribute descriptions to the entity descriptions and the entity descriptions to the managed object context.
versionEntity.properties = @[versionValueDescription];
versionEntity.properties = @[versionValueDescription, versionDateDescription];
childEntity.properties = @[childNameDescription, childBiographyDescription, childGenderDescription, childBirthdayDescription, childThumbnailDescription, childMediaDescription];
mediaEntity.properties = @[mediaUrlDescription, mediaTypeDescription];
managedObjectModel.entities = @[versionEntity, childEntity, mediaEntity];
Expand Down
4 changes: 2 additions & 2 deletions ToyLoadingScreen/ToyLoadingScreen/HGMediaItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

@interface HGMediaItem : NSManagedObject

@property (nonatomic, strong) NSString* url;
@property (nonatomic, strong) NSString* type;
@property (nonatomic, strong) NSString *url;
@property (nonatomic, strong) NSString *type;

+ (HGMediaItem *)addMediaItemFromData:(NSDictionary *)data toContext:(NSManagedObjectContext *)context;

Expand Down
3 changes: 2 additions & 1 deletion ToyLoadingScreen/ToyLoadingScreen/HGVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

@interface HGVersion : NSManagedObject

@property (nonatomic, strong) NSString* value;
@property (nonatomic, strong) NSString *value;
@property (nonatomic, strong) NSDate *date;

+ (HGVersion *)addVersion:(NSString *)value toContext:(NSManagedObjectContext *)context;

Expand Down
2 changes: 2 additions & 0 deletions ToyLoadingScreen/ToyLoadingScreen/HGVersion.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
@implementation HGVersion

@dynamic value;
@dynamic date;

// Add a media item entity to the managed object context and populate it with data from a JSON dictionary.
+ (HGVersion *)addVersion:(NSString *)value toContext:(NSManagedObjectContext *)context {
HGVersion *version = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([self class]) inManagedObjectContext:context];
version.value = value;
version.date = [NSDate date];
return version;
}

Expand Down
3 changes: 1 addition & 2 deletions ToyLoadingScreen/ToyLoadingScreen/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

#import "HGAppDelegate.h"

int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([HGAppDelegate class]));
}
Expand Down

0 comments on commit 06682dd

Please sign in to comment.