views:

447

answers:

2

Hi,

I have a problem with the init() method of a standard NSObject. I wrote a class (EFAPersistence) which is a subclass of NSObject. EFAPersistance has a attribute called efaDatabase.

EFAPersistence.h

@interface EFAPersistence : NSObject {
  FMDatabase * efaDatabase;
}

@property (assign) FMDatabase * efaDatabase;

Everytime an instance of EFAPersistance is created I want to assign efaDatabase a value from my AppDelegate.

EFAPersistence.m

@implementation EFAPersistence

@synthesize efaDatabase;

- (id)init {
  if (self = [super init]) {
    efaDatabase = [[NSApp delegate] efaDatabase];
  }
  return self;
}

@end

This way of assigning does not work. But it works if I put the code in a normal method. So I am sure that efaDatabase is correctly instantiated in my AppDelegate. It's just not working in my init() method. That's why I have the feeling that NSApp is not working inside the init() method.

That's how the important AppDelegate code looks like.

AppDelegate.h

@interface AppDelegate : NSObject <NSApplicationDelegate> {
  FMDatabase * efaDatabase;
}

AppDelegate.m

- (id)init {
  if (self = [super init]) {
    NSString * databasePath = 
      [[NSBundle mainBundle] pathForResource:@"efa" ofType:@"sqlite"];

    self.efaDatabase = [FMDatabase databaseWithPath:databasePath];

    if (![efaDatabase open]) {
      NSLog(@"Couldn't open database: %@", databasePath);
      // TODO: Create a database here
    }
    self.db = [[EFAPersistence alloc] init];
  }
  return self;
}

As you can see I am calling the init method. I also affirmed this by using NSLog(). init() is called. The attribute I am trying to assign in EFAPersistence is also created before init() is called.

To sum everything up:

How can I make this work within the init() method so I do not have to write boiler plate code in all my methods of EFAPersistence?

+2  A: 

It looks to me that your AppDelegate is unset when you try to create the EFAPersistance object the first time. This is on below line in AppDelegate.m

self.db = [[EFAPersistence alloc] init];

I imagine the app delegate is set after the init is done (returned).

epatel
I also think that NSApp is created/assigned or whatever after init(). The question is how to assign efaDatabase in EFAPersistences only once . There are other methods like awakeFromNib and viewDidLoad etc. But those are not available in a plain NSObject subclass.
Jens
@Jens How about doing `self.db.efaDatabase = efaDatabase;` right after the line I referred to above?
epatel
Setting efaDatabase on self.db, after instantiating it, worked. Thank you all.
Jens
+4  A: 

This way of assigning does not work. But it works if I put the code in a normal method. So I am sure that efaDatabase is correctly instantiated in my AppDelegate. It's just not working in my init() method. That's why I have the feeling that NSApp is not working inside the init() method.

NSApp works fine.

Quoting epatel:

I imagine the app delegate is set after the init is done (returned).

Correct. The nib loader completely instantiates each object (including the app delegate, if it's in a nib), then sets it as the value of any properties it's connected to. These are two separate operations; it will not set a not-yet-initialized object as the application delegate.

Quoting you (Jens) again:

The question is how to assign efaDatabase in EFAPersistences only once . There are other methods like awakeFromNib and viewDidLoad etc. But those are not available in a plain NSObject subclass.

Incorrect. awakeFromNib is sent to every object in a nib after the object has been initialized.

That said, I'm curious as to why you have EFAPersistence in a nib. From its name, it doesn't sound interface-related. Shouldn't the app delegate own the EFAPersistence, and the EFAPersistence own the database directly?

Peter Hosey