I am modularizing some of my code in order to make it reusable in future projects. The latest thing that I have created is a simple class that saves user profiles. The list of profiles is loaded into a view, and the user can add a new profile to the list and select which profile is currently active. When a profile is added to the list a directory with a matching name is created. All files unique to that user will be saved in their directory.
In other classes, objects will check if there is a current active profile (by looking for the existence of a certain file). If it exists, the objects will save and load using the active profile directory.
I'm looking for any kind of feedback on this code, but specifically, am I using class methods in an appropriate way? Is the interface easy to understand? I'm not planning to make a public library, but I would still like to do things in the best way possible.
MPProfileTools.h
#import <Foundation/Foundation.h>
@interface MPProfileTools : NSObject
//profiles are stored as an array of strings
+(NSMutableArray *) allProfiles;
+(void) saveProfileList:(NSMutableArray *)profileList;
//name of the current active profile
+(NSString *) activeProfile;
//create the directory and the active profile file
+(void) setActiveProfile:(NSString *)profile;
//deletes the associated directory
//also deletes the active profile file if it is currently selected
+(void) deleteProfile:(NSString *)profile;
@end
MPProfileTools.m
#import "MPPathTools.h"
#import "MPProfileTools.h"
@implementation MPProfileTools
+(NSMutableArray *) allProfiles {
NSString *path = [MPPathTools allProfilesPath];
NSMutableArray *profilesToLoad = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
return profilesToLoad;
}
+(void) saveProfileList:(NSMutableArray *)profileList {
NSString *path = [MPPathTools allProfilesPath];
[NSKeyedArchiver archiveRootObject:profileList toFile:path];
}
+(NSString *) activeProfile {
return [NSKeyedUnarchiver unarchiveObjectWithFile:[MPPathTools currentActiveProfileFile]];
}
+(void) setActiveProfile:(NSString *)profile {
NSString *fileName = [MPPathTools currentActiveProfileFile];
[NSKeyedArchiver archiveRootObject:profile toFile:fileName];
[MPProfileTools createDirectoryNamed:profile];
}
+(void) createDirectoryNamed:(NSString *)directoryName {
NSString *pathToCreate = [[MPPathTools applicationDocumentsPath] stringByAppendingPathComponent:directoryName];
[[NSFileManager defaultManager]createDirectoryAtPath:pathToCreate withIntermediateDirectories:NO attributes:nil error:nil];
}
+(void) deleteProfile:(NSString *)profile {
NSString *pathToDelete = [[MPPathTools applicationDocumentsPath] stringByAppendingPathComponent:profile];
[[NSFileManager defaultManager]removeItemAtPath:pathToDelete error:nil];
//delete the active profile file so that the title screen cannot render it when it doesnt exist
if ([profile isEqualToString:[MPProfileTools activeProfile]]) {
[[NSFileManager defaultManager]removeItemAtPath:[MPPathTools currentActiveProfileFile] error:nil];
}
}
@end
Here is some sample usage for the class:
MPProfileTableViewController.m
#import "MPProfileTableViewController.h"
#import "MPProfileTools.h"
@implementation MPProfileTableViewController {
UITableView *_tableViewToDeleteFrom;
NSIndexPath *_indexPathToDelete;
}
typedef NS_ENUM (NSInteger, MPAlertViewType) {
MPAlertViewTypeAdd = 0,
MPAlertViewTypeDelete
};
-(void) viewDidLoad {
[super viewDidLoad];
[self loadProfilesForRender];
}
#pragma mark - Select Profile
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *profileName = [self.profiles objectAtIndex:indexPath.row];
[MPProfileTools setActiveProfile:profileName];
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - Delete Profile
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//save the variables before creating the alert
_tableViewToDeleteFrom = tableView;
_indexPathToDelete = indexPath;
[self popupDeleteWarningBox];
}
}
-(void) deleteProfile {
NSString *profileName = [self.profiles objectAtIndex:_indexPathToDelete.row];
// Delete the row from the data source
// use the saved variables to delete the profile from disk
if (_tableViewToDeleteFrom && _indexPathToDelete) {
[self.profiles removeObjectAtIndex:_indexPathToDelete.row];
[_tableViewToDeleteFrom deleteRowsAtIndexPaths:@[_indexPathToDelete] withRowAnimation:UITableViewRowAnimationFade];
[MPProfileTools deleteProfile:profileName];
_tableViewToDeleteFrom = nil;
_indexPathToDelete = nil;
}
}
#pragma mark - Save and load profiles
-(void) loadProfilesForRender {
self.profiles = [MPProfileTools allProfiles];
}
-(void) viewWillDisappear:(BOOL)animated {
[MPProfileTools saveProfileList:self.profiles];
}
#pragma mark - Alert Popups
-(void) popupDeleteWarningBox {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Warning"
message:@"Deleting a profile will delete all the saved information for that profile!"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Confirm", nil];
alert.tag = MPAlertViewTypeDelete;
[alert show];
}
- (void) popupAddItemBox {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Profile Name"
message:@"Input your profile name below:"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Done", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
alert.tag = MPAlertViewTypeAdd;
[alert show];
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == MPAlertViewTypeAdd) {
if (buttonIndex == [alertView cancelButtonIndex]) {
//cancel clicked
} else {
//done clicked
UITextField *textField = [alertView textFieldAtIndex:0];
[self.profiles addObject:textField.text];
[MPProfileTools setActiveProfile:textField.text];
[self.tableView reloadData];
}
} else if (alertView.tag == MPAlertViewTypeDelete) {
if (buttonIndex == [alertView cancelButtonIndex]) {
//cancel clicked
} else {
//confirm clicked
[self deleteProfile];
}
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.profiles count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [self.profiles objectAtIndex:indexPath.row];
return cell;
}
@end
I'm not very experienced with subclassing table views or using UIAlertViews, so there may be code that is ripe for review in the above.