Reputation: 30
I'm trying to access a property in my app delegate from another class (something I thought would be rather simply) but I'm having troubles in doing so. My files currently look like this:
LTAppDelegate.h
#import <Cocoa/Cocoa.h>
#import "Subject.h"
@interface LTAppDelegate : NSObject <NSApplicationDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate> {
}
@property Subject *selectedSubject;
@end
LTAppDelegate.m
@synthesize selectedSubject;
The value for selectedSubject is then set inside applicationDidFinishLaunching
in LTAppDelegate.m. Now I'm wanting to get access to this from another class that I have, which is called LTTableViewController and is setup like so:
LTTableViewController.h
#import <Foundation/Foundation.h>
#import "LTAppDelegate.h"
#import "Subject.h"
#import "Note.h"
@interface LTTableViewController : NSObject{
NSMutableArray *notesArray;
LTAppDelegate *appDelegate;
Subject *s;
}
-(IBAction)currentSubjectDetails:(id)sender;
@end
LTTableViewController.m
#import "LTTableViewController.h"
@implementation LTTableViewController
- (id)init
{
self = [super init];
if (self) {
appDelegate = ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]);
s = [appDelegate selectedSubject];
NSLog(@"Test Subject: %@", [s title]);
}
return self;
}
-(IBAction)currentSubjectDetails:(id)sender{
NSLog(@"Selected Subject: %@", [s title]);
}
After inserting various NSLog() messages it would appear that the init method of LTTableViewController is called before applicationDidFinishLaunching
is called in LTAppDelegate. Based on that it makes sense that the "Test Subject" NSLog() in LTTableViewController.m init displays null; however, the 'currentSubjectDetails' method is linked to a button on the interface and when that is pressed after the app is finished loading, the NSLog() message still returns null.
Is there anything obvious I'm missing here. I feel like I'm being a little stupid and missing something really basic.
Upvotes: 0
Views: 1011
Reputation: 183
-applicationDidFinishLaunching
called when e.g. all nib's object initialized, so launching will be ended after construction of views related stuff. This means that constructors of nib's objects wouldn't use any other nib's objects (your delegate and controller initializing with nib, right?).
Try to use -awakeFromNib
instead of constructors, I think it will called after construction of both objects.
If you are trying to avoid often calls of ((LTAppDelegate *)[[NSApplication sharedApplication] delegate])
I'll recommend to pass it as method parameter, in function stack. Cyclic references defense and some flexibility.
Upvotes: 1
Reputation: 5569
Well, s
does not exist, since it is set to null in init
, so -currentSubjectDetails
prints null. It is not a good idea to set your private variables in the constructor if they depend on other objects.
Rather, let the other objects explicitly tell your controller that it should use that Subject
(e.g., treat s
as a property).
Or, just query ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]);
every time.
Upvotes: 1
Reputation: 16790
Similar issue is described here http://iphonedevsdk.com/forum/iphone-sdk-development/11537-viewcontroller-called-before-applicationdidfinishlaunching.html Adding this kind of functionality in the constructor is usually not recommended. Generally, I'd suggest using parameters and not relying on hidden dependencies as those will necessarily depend on the order of execution and you lose the help of the compiler to avoid invalid values. View controller initializers should not be used to store mutable references since view controllers are initialized automatically by predefined constructors, and you cannot pass parameters to them this way.
If you need to access the app delegate, then obtain it, perform operations on it and drop the reference. Try not to cache it, you'll very likely introduce hidden issues. I suggest you hook into the appear-disappear cycle if the viewed contents depend on any kind of current state.
Upvotes: 2