UITableView is a view object, so, according to Model-View-Controller, it knows how to draw itself, but that's it.
UITableView needs a data source to ask for data, a delegate to inform events involving the UITableView, and typically a view controller to create and destroy instance of UITableView.
a singleton
#import@interface PossessionStore : NSObject{}// Notice that this is a class method, and is prefixed with a + instead of a -+ (PossessionStore *)defaultStore;@end
at the top of .m file, create a global static variable to hold the instance variable.
#import "PossessionStore.h"#import "Possession.h"static PossessionStore *defaultStore = nil;@implementation PossessionStore
Also, in .m file, implement +defaultStore, +allocWithZone: and -init so that only one instance of the class can be created.
+ (PossessionStore *)defaultStore{if (!defaultStore) {// Create the singletondefaultStore = [[super allocWithZone:NULL] init];}return defaultStore;}// Prevent creation of additional instances+ (id)allocWithZone:(NSZone *)zone{return [self defaultStore];}- (id)init{// If we already have an instance of PossessionStore...if (defaultStore) {// Return the old onereturn defaultStore;}self = [super init];return self;}
Now, override the retain count methods so that no one can release the defaultStore.
- (id)retain{// Do nothingreturn self;}- (void)release{// Do nothing}- (NSUInteger)retainCount{return NSUIntegerMax;}
Now you have a singleton.
Reuse UITableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath{// Check for a reusable cell first, use that if it existsUITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];// If there is no reusable cell of this type, create a new oneif (!cell) {cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:@"UITableViewCell"] autorelease];}Possession *p = [[[PossessionStore defaultStore] allPossessions]objectAtIndex:[indexPath row]];[[cell textLabel] setText:[p description]];return cell;}
Editing Mode
UITableView has an editing property, and when this property is set to YES, the UITableView enters editing mode. Editing mode does not allow the user to edit the content of a row.
In the toggleEditingMode: method, you could toggle the editing property of UITableView directly. However, UITableViewController also has an editing property. A UITableViewController instance automatically sets the editing property of its table view to match its own editing property. Which one should you set? Follow the Model-View-Controller pattern: talke to the controller and let the controller talk to the view.
- (void)toggleEditingMode:(id)sender{// If we are currently in editing mode...if ([self isEditing]) {// Change text of button to inform user of state[sender setTitle:@"Edit" forState:UIControlStateNormal];// Turn off editing mode[self setEditing:NO animated:YES];} else {// Change text of button to inform user of state[sender setTitle:@"Done" forState:UIControlStateNormal];// Enter editing mode[self setEditing:YES animated:YES];}}
Adding Rows
We are going to put a New button in the header view to allow adding a row.
- (IBAction)addNewPossession:(id)sender{[[PossessionStore defaultStore] createPossession];// tableView returns the controller's view[[self tableView] reloadData];}
Deleting Rows
Before the table view will delete a row, it sends its data source a message about the deletion and waits for confirmation before pulling the trigger.
delete from datasource, not just from UITableViewController.
- (void)tableView:(UITableView *)tableViewcommitEditingStyle:(UITableViewCellEditingStyle)editingStyleforRowAtIndexPath:(NSIndexPath *)indexPath{ // If the table view is asking to commit a delete command... if (editingStyle == UITableViewCellEditingStyleDelete) { PossessionStore *ps = [PossessionStore defaultStore]; NSArray *possessions = [ps allPossessions]; Possession *p = [possessions objectAtIndex:[indexPath row]]; [ps removePossession:p]; // We also remove that row from the table view with an animation [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; }}
Moving Rows
you will use another method from the UITableViewDataSource protocol – tableView:moveRowAtIndexPath:toIndexPath:.
- (void)movePossessionAtIndex:(int)from toIndex:(int)to{ if (from == to) { return; } // Get pointer to object being moved Possession *p = [allPossessions objectAtIndex:from]; // Retain it... (retain count of p = 2) [p retain]; // Remove p from array, it is automatically sent release (retain count of p = 1) [allPossessions removeObjectAtIndex:from]; // Insert p in array at new location, retained by array (retain count of p = 2) [allPossessions insertObject:p atIndex:to]; // Release p (retain count = 1, only owner is now array) [p release];}
Now, in implement tableView:moveRowAtIndexPath:toIndexPath: to update the store.
- (void)tableView:(UITableView *)tableViewmoveRowAtIndexPath:(NSIndexPath *)fromIndexPathtoIndexPath:(NSIndexPath *)toIndexPath{ [[PossessionStore defaultStore] movePossessionAtIndex:[fromIndexPath row] toIndex:[toIndexPath row]];}