i am creating an application that needs to work with categories.
there will be a basic categories set that i want to deliver with the app, but it can be edited by the user (remove, add categories). the basic .plist will not be changed but read just once, and then stored mutable somewhere else.
here is my approach:
Default Categories delivered in categoryCollection.plist with the app.
defaultCategories.plist will be the new .plist file that gets manipulated

categoryCollection.plist
to read the categories into a NSMutableSet i use:
NSString *mainBundlePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dictPath = [mainBundlePath stringByAppendingPathComponent:@"defaultCategories"];
NSDictionary * dict = [[NSDictionary alloc]initWithContentsOfFile:dictPath];
// testing if the file has values, if not load from categoryCollection.plist
if (dict.count == 0) {
NSString *tempPath = [[NSBundle mainBundle] pathForResource:@"categoryCollection" ofType:@"plist"];
dict = [NSMutableDictionary dictionaryWithContentsOfFile:tempPath];
[dict writeToFile:dictPath atomically:YES];
}
// load into NSMutableSet
[self.stringsCollection addObjectsFromArray:[[dict objectForKey:@"categories"]objectForKey:@"default"]];
to add a category i call this function:
-(void)addCategoryWithName:(NSString *)name{
NSString *mainBundlePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dictPath = [mainBundlePath stringByAppendingPathComponent:@"defaultCategories"];
NSMutableDictionary * dict = [[NSMutableDictionary alloc]initWithContentsOfFile:dictPath];
[[[dict objectForKey:@"categories"]objectForKey:@"default"]addObject:name];
[dict writeToFile:dictPath atomically:YES];
self.needsToUpdateCategoryCollection = YES;
}
and to delete a string i use:
-(void)removeCategoryWithName:(NSString *)name{
NSString *mainBundlePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dictPath = [mainBundlePath stringByAppendingPathComponent:@"defaultCategories"];
NSDictionary * dict = [[NSDictionary alloc]initWithContentsOfFile:dictPath];
NSMutableArray *temp = [NSMutableArray arrayWithArray:[[dict objectForKey:@"categories"]objectForKey:@"default"]] ;
for (NSString *string in temp) {
if ([string isEqualToString:name]) {
[temp removeObject:string];
break;
}
}
[[dict objectForKey:@"categories"]removeObjectForKey:@"default"];
[[dict objectForKey:@"categories"] setValue:temp forKey:@"default"];
[dict writeToFile:dictPath atomically:YES];
self.needsToUpdateCategoryCollection = YES;
}
the code actually works quite well, but i wonder if this massive overhead of multiple I/O operations, tests etc is really necessary or if there is a more elegant solution to store a collection of strings and let them be manipulated?
or if you see any speedbump that might improve the speed (because i get some small lags with that code when having a lot of categories)
any thoughts?
sebastian
Your approach works fine, but it does more work than it is necessary by writing the results every time the collection is modified. It is writing of the file that is the costliest part of your
addandremovemethods.One way to address the problem would be to read your categories when your app starts up, cache your
NSMutableDictionaryin a singleton object, and reference it as your app runs. When end users make changes, you update the dictionary only in memory; do not write the data to the file immediately.In your app delegate, listen to the
applicationDidEnterBackground:event, and write the data to the file in that handler. Also listen to theapplicationDidEnterForeground:event, and read your file intoNSMutableDictionary. This will save you a lot of CPU cycles, and provide smoother end-user experience.