views:

3964

answers:

4

Hi!

I'd like to create database based models, so I wanna use my own DatabaseModel class to manage the database connection, and every class that uses database is derived from it (it would be a mapping between the model and the table). I'm using a sqlite API.

Since I need only one database connection instance, I created a static variable to store the connection instance

DatabaseModel.h
---------------

@interface DatabaseModel : NSObject {
}

// the connection instance
static FMDatabase *database;

+(BOOL) open;
+(void) close;

+(id)getDatabase;

@end


DatabaseModel.m
---------------

// Is it necassary?
static FMDatabase *database = nil;

@implementation DatabaseModel
+(BOOL) open
{
    // make connection (doodled code)
    database = [DBAPI open];
}

+(void) close
{
    // ...
}

+(id)getDatabase
{
    // Throws bad_memory_access
    [database retain];
    return database;    
}
@end


MyClass.h
---------

@interface MyClass : DatabaseModel
{
}

-(void) foobar;
@end


MyClass.m
---------

@implementation MyClass
-(void) foobar
{
    // This assign doesn't work
    database = [DatabaseModel getDatabase];
}
@end

In this case [database retain] throws a bad_access exception. I don't understand exactly, when database is a static variable, why I get this message...

A: 

This error actually saying that the database variable is still null. I dont see any init call of the database variable or allocation. Am I missing anything?

yn2
+3  A: 
  1. It doesn't look like you create the object anywhere. You need to alloc and init the object before you can use it.
  2. You should not be retaining the static object every time someone calls +getDatabase. This will cause the object to be over retained and there is really no reason for it, once you alloc and init it then the static variable will own it and you don't need any more retains.

Cocoa has a design pattern call Singleton that would work well here. You create a single instance of a class and then have a method (often along the lines of +sharedClassName) that returns that instance.

For more reading there is some good information at CocoaDev regarding the singleton design pattern and Cocoa with Love has a good article on Singletons, AppDelegates and top-level data.

Nathan Kinsinger
1. In the open method it is allocated by the APII don't wanna use singleton, because it's not a typical singleton case. There will be more derived classes, and I just want to use the same database connection in all classes. (Thread safe be my problem..) So I open the connection in the beginning of the application, and close when the program terminates.Thanks for the links...
A: 

Sorry guys!

It was my mistake. In Open() function the API asks for an (NSString*) sqlite path. And I forgot to retain that variable. (I'm sometimes in trouble with objective-c memory management, sorry)

Now I'm creating the variable without static keyword on the base class, and using extern keyword to reach in the subclasses, and does it work.

With static keyword it's invisible from derived classes...

A static variable is only available in the file it's declared in. Your subclasses would have to call the +getDatabase method to get a reference to it.
Nathan Kinsinger
A: 

In your +open method, you have:

database = [DBAPI open];

If DBAPI is following standard Cocoa memory rules, the returned instance is not retained (usually it's autoreleased). So by the time you access it in +getDatabase the instance may already have been released.

Simple fix would be to retain the instance:

database = [[DBAPI open] retain];

A better approach would be to adopt the singleton pattern as others have mentioned.

Daniel Dickison