views:

20

answers:

2

My data is stored in a member variable (NSArray) of a view controller. The problem I'm running into is that my data is loaded from a database on application launch, but the NSArray isn't initialized until later, so the addObject calls silently fail.

I've tried putting breakpoints on the init, initWithNibName, viewWillAppear, and viewDidLoad methods of my view controller (SafeTableViewController), but none of them catch before the addObject call. I assume that the actual view controller is initialized, because when I watch it in the debugger it has a nonzero address, but the NSArray has the address 0x0 when addObject is called.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    databaseName = @"DubbleDatabase.sql";

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [documentPaths objectAtIndex:0];
    databasePath = [documentsDir stringByAppendingPathComponent:databaseName];

    [self checkAndCreateDatabase];

    [self readSafeItemsFromDatabase ];

    // Add the tab bar controller's current view as a subview of the window
    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];

    return YES;
}
- (void) readSafeItemsFromDatabase {
    // some code skipped here, but basically: open sqlite3 database, iterate through rows

            while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
                // read database, get data fields out

                SafeItem *safeItem = [[SafeItem alloc] initWithName:aName price:aPrice category:aCategory];

                [safeTableViewController addItemToSafe: safeItem]; // PROBLEM HERE

                [safeItem release];
            }
    }
    sqlite3_close(database);
}

In SafeTableViewController.m:

- (void) addItemToSafe : (SafeItem*) newSafeItem {
    [self.safeItems addObject: newSafeItem]; 
}

// I put a breakpoint on this, but it does not hit.  i.e. safeItems is not initialized when addObject is called on it.
-(id) init {
    if(self = [super initWithNibName:@"SafeTableViewController" bundle:nil]){
        self.safeItems = [[NSMutableArray alloc] init];
    }
    return self;
}

EDIT: Thought of a way to fix this problem. Still curious though: when is init and/or initWithNibName called? Here's the proposed solution:

- (void) addItemToSafe : (SafeItem*) newSafeItem {
    if(self.safeItems == nil){
        self.safeItems = [[NSMutableArray alloc] init];
    }
    [self.safeItems addObject: newSafeItem]; 
}
+1  A: 

The problem is that you shouldn't be storing your data in a view controller. Create a model object (SafeItemManager for instance) to hold your data and point the view controller at that.

Rob Napier
okay. i created SafeItemManager. Would you recommend making this the UITableView's dataSource? (Then I would move all of the methods like tableView:commitEditingStyle:forRowAtIndexPath: into SafeItemManager, which feels a little funny since SafeItemManager feels like a pure-data object.
unsorted
No, the ViewController should be the datasource. It should just query the SafeItemManager for the data. You're correct that SIM is now a pure data object.
Rob Napier
+1  A: 

How do you setup your instance of SafeTableViewController? By code? By nib?

-(id) init is not the designated initializer.

You probably want to use

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    if(self = [super initWithNibName:nibName bundle:nibBundle]){
        self.safeItems = [[NSMutableArray alloc] init];
    }
    return self;
}

or initialize elsewhere, i.e. in viewDidLoad.

Eiko
I think this is right. I ended up moving my data to a separate manager as suggested in the other answer, but looking back, since I'm using a nib file it should call `initWithNibName` instead of `init` anyway. Thanks.
unsorted