Today I would like to share with you a little piece of code that I find very handy. A class that helps you managing “updates”. I use it in my apps that work with cached data. You could encounter the situation where you need to develop an app that queries a web service to obtain the data to be shown on the device.
However, sometimes the information you need to access doesn’t change so often and it is not necessary to bother the user with a loading message only to end up showing the same information than 2 minutes before. If being up to date accurately is not critical for your app, the code I’m going to show may help you.
The files
I have named this class “UpdateManager“. It is a static methods based class that uses the NSUserDefaults to store the needed data. So, you won’t need to allocate it. Here you have the UpdateManager.h file:
#import <Foundation/Foundation.h> #define kKeyLastUpdate @"lastUpdate" #define kDaysToUpdate 1 @interface UpdateManager : NSObject { } +(NSString*) getLastUpdate; +(NSDate*) getLastUpdateNSDate; +(void) setLastUpdate:(NSString*)lastUpdateString; +(void) setLastUpdateNSDate:(NSDate*)lastUpdate; +(void) initialize; +(void) setLastUpdateToday; +(BOOL) needUpdate; @end
Here you have several methods. However, the ones that you will probably use most are the three last ones: initialize, setLastUpdateToday and needUpdate. Actually, the other methods are utility methods used by those three.
Let’s have a look to the implementation of all those methods above:
#import "UpdateManager.h" @implementation UpdateManager +(void) initialize { if([UpdateManager getLastUpdateNSDate] == nil) { [UpdateManager setLastUpdateToday]; } } +(NSString*) getLastUpdate { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSDate *lastUpdate = (NSDate*)[userDefaults objectForKey:kKeyLastUpdate]; NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"dd-MM-yyyy"]; NSString *lastUpdateString = [dateFormat stringFromDate:lastUpdate]; [dateFormat release]; return lastUpdateString; } +(NSDate*) getLastUpdateNSDate { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSDate *lastUpdate = (NSDate*)[userDefaults objectForKey:kKeyLastUpdate]; return lastUpdate; } +(void) setLastUpdateNSDate:(NSDate*)lastUpdate { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:lastUpdate forKey:kKeyLastUpdate]; } +(void) setLastUpdate:(NSString*)lastUpdateString { NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"dd-MM-yyyy"]; NSDate *lastUpdate = [dateFormat dateFromString:lastUpdateString]; [dateFormat release]; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:lastUpdate forKey:kKeyLastUpdate]; } +(void) setLastUpdateToday { [UpdateManager setLastUpdateNSDate:[NSDate date]]; } +(BOOL) needUpdate { NSInteger daysSinceLastUpdate = [[NSDate date] timeIntervalSinceDate:[UpdateManager getLastUpdateNSDate]] / 86400; if (daysSinceLastUpdate >= kDaysToUpdate) { return YES; } else { return NO; } } @end
Nothing extremely fancy here. As I said, I use NSUserDefaults to store the date of the last update. The key used to store this information is defined by the constant “kKeyLastUpdate“. I use NSDateFormatter to manage all the string date stuff, in case it was needed.
The constant “kDaysToUpdate” defines the frequency the data should be updated on (in days). In the “needUpdate” method I use a 86400 magic number to calculate the days since last update. 86400 are the number of seconds corresponding to a whole day (24 hours). NSDate returns the time interval in seconds, so I need to convert them to days.
Usage
The usage of this class is very very simple. First, you need to initialize it just after launching your app. I usually do it at my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Add this line of code [UpdateManager initialize]; return YES; }
Then, whenever you need to check for the update you call the needUpdate method. I usually do it when the app comes to foreground:
- (void)applicationWillEnterForeground:(UIApplication *)application { // Add this code if ([UpdateManager needUpdate]) { // Start updating the needed information. } }
Finally, if the update process went OK you need to update the last update date:
//Whenever the update process has finished OK... [UpdateManager setLastUpdateToday];
Conclusion
And that’s it! I use this class to update cached data but you could use it for whatever you want: send periodical local notifications, count the time elapsed from the last time a user launched your app, etc.
Do whatever you want with it! 😉
This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.
Thank you for sharing. Caching the list of Facebook friends has been on my to do list for a while now.
Good idea, it’s actually very handy. I will certainly use that in some of my projects, it makes things clearer and more maintainable.
I would have a remark about the architecture though. I don’t think that using all class methods are good design. I would make them object methods. And I would store the key string and the interval as ivars set at initialisation time:
– (id)initWithKey:(NSString *)key refreshInterval:(NSTimeInterval)interval;
If you really find it convenient to have class methods, just use the singleton design pattern :
+ (UpdateManager *)defaultManager;
and make your calls to that singleton, e.g.:
[[UpdateManager defaultManager] setLastUpdateToday];
Finally, a word about naming conventions. setLastUpdateNSDate: and getLastUpdateNSDate: are poor choices. Objective-C methods are usually meant as a phrase, you should be able to tell what it does just by the name without being familiar with the implementation, and that’s not the case with these names. Usually, you don’t repeat the maker/library prefix either (NS, CL, CF, UI, MK, CG…). A better rename might therefore be setLastUpdateWithDate: and getLastUpdateDate, for example (and similarly setLastUpdateWithString: and getLastUpdateString for the NSString equivalent — maybe even with an optional locale: setLastUpdateWithString:locale: and getLastUpdateStringWithLocale:). I would also rename the setLastUpdateToday method to setLastUpdateNow, as it’s closest to what the method actually do, and does no make assumptions about the refresh time interval.
HTH 🙂
Wow! Thank you very much for your comments!
I was thinking about the singleton solution. However, personally, I don’t like the complexity that the calls to the singleton have in Objective-C:
[[UpdateManager defaultManager] setLastUpdateToday];
vs.
[UpdateManager setLastUpdateToday];
Two words better than three. And two brackets better than four :p When the class is simple enough, I usually use the static method design. However, I agree with you that the singleton patter may be more suitable from the design point of view.
And about the naming conventions, yes I absolutely agree with you. I’m used to deal with dates as strings, that’s why when the method deals with NSDates I write it explicitly on the signature. Just to remember me. However, that’s my problem 😀 The names you suggest are better choices.
I will take all your feedback into account when working on the next version of the class 🙂
Thanks a lot!
You’re welcome!
Thank’s for sharing your code snipped, maybe I will use it on my next game.