My application loads a local list.plist
file at launch.
Then it has a refreshTable button which fetch a remote version of the .plist file from my website.
App Launch
local list.plist loads
user hits refreshList button
local list.plist is overwritten by remote list.plist
local list.plist updated until remote list.plist updates again
Method to initialize data:
//Remote data
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
//Local data
NSString *localPath = [[NSBundle mainBundle] pathForResource:@"list" ofType:@"plist"];
localList = [[NSMutableArray alloc] initWithContentsOfFile:localPath];
NSSortDescriptor *localDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:localDescriptor]] retain];
This is the method to refresh:
- (void) refreshTable:(id)sender
{
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
[self.tableView reloadData];
//now write remote plist to local plist
}
After i downloaded the remote plist how can i write over the local plist?
I was thinking to empty the local array containing the local plist and fill it with the remote array and i did it this way:
I solved in the way i thought:
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://phillipapps.com/mntlion/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(@"list: %@",list);
[localList removeAllObjects];
[localList addObjectsFromArray:list];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(@"locallist: %@",localList);
[self.tableView reloadData];
It works, but how can i write over localList
with the contents of list
?
so … after a view hours in chat we got the problem solved.
- (NSArray*)readPlist
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:@"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:@"template" ofType:@"plist"];
}
return [NSArray arrayWithContentsOfFile:plistPath];
}
- (void)writePlist:(NSArray*)arr
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:@"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath])
[fMgr removeItemAtPath:plistPath error:nil];
[arr writeToFile:plistPath atomically:YES];
}
initializing the ivar:
self.plistArray = [self readPlist];
and after loading the new plist
from the server you have to call this code:
self.plistArray = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:@"http://mywebsite.com/list.plist"]];
[self writePlist:plistArray]; // e.g. for caching
[self.tableView reloadData];
I do almost the exact thing you're looking for in an application of mine. You can't write to the NSBundle so the steps are something like this:
Try to load plist from cache directory, if it succeeds go to 3.
Load plist from bundle
Check if loaded plist is up to date (or, trigger further steps by the press of a button)
Download new plist
Save to cache directory
The code looks something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
ratios = [NSDictionary dictionaryWithContentsOfFile:[cache stringByAppendingPathComponent:@"devices.plist"]];
if (ratios == nil) {
ratios = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"devices" ofType:@"plist"]];
}
NSString *device = [[UIDevice currentDevice] machine];
NSDictionary *d = [ratios objectForKey:device];
if (d!=nil) {
pixelInchRatio = [[d objectForKey:@"pixelInchRatio"] doubleValue];
bezelWidth = [[d objectForKey:@"bezelWidth"] doubleValue];
bezelHeight = [[d objectForKey:@"bezelHeight"] doubleValue];
} else if (fetch) {
[[[[RulerDimensionDownload alloc] init] autorelease] startDownload];
}
Then in the downloader it saves like so:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
[[NSFileManager defaultManager] createDirectoryAtPath:cache withIntermediateDirectories:YES attributes:nil error:nil];
[ratios writeToFile:[cache stringByAppendingPathComponent:@"devices.plist"] atomically:YES];
Some explanations:
The first few lines in each sample, the paths and cache definition, simply get the location of the cache directory for the application. I use this to store the most up-to-date version I'm my plist.
So, in the loading code, I first try to load the plist from the cache directory. If this fails (ratios is null) I then load it from my application bundle (this is the version of the plist that I ship with the app).
After that, I check to see if the plist has the information needed. (the plist has a definition for each device type. If the device isn't in the plist then I know I need to try to update the plist)
If the plist is out of date I start the download using a class I wrote: RulerDimensionDownload. Once it completes the download I save the file into the cache directory. Then, next time the plist needs to be loaded it will be loaded first and the shipped plist will never be looked at. (I also send a notification with the new plist)