Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
119 views
in Technique[技术] by (71.8m points)

objective c - Sharing an object between two classes

I'm developing an app for OS X and I got stuck with a problem.

The structure of the app is :

  • AppDelegate: where the main actions take place from MainMenu.xib. It's also where the main window is created.

  • SettingsWindowController: where a settings window is defined with interface from SettingsWindow.xib.

  • I created a protocol SettingsWindowProtocol to delegate those two classes.

  • I created one more class dbHandler which is initialized as an obj dbh in AppDelegate.

  • In SettingsWindowProtocol I created a method to send the object but after I call this method in SettingsWindowControl the object is null.

The question is how I share in two different classes the same object ?

A few blocks of code related to question:

AppDelegate.h:

#import "dbHandler.h"    

...

@property (retain) dbHandler *dbh;
@interface AppDelegate : NSObject <SettingsWindowControllerProtocol>

-(dbHandler*)sendDBobject;

AppDelegate.m:

...
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{   
    dbh = [[dbHandler alloc]init];
    ...
}

- (IBAction)settingsButton:(id)sender {
    if(!settingsWindowController){
        settingsWindowController = [[SettingsWindowController alloc] initWithWindowNibName:@"SettingsWindow"];
    }

    [settingsWindowController showWindow:self];
    settingsWindowController.delegate = self;
}

-(dbHandler*)sendDBobject{
    return dbh;
}

SettingsWindowController.h :

#import "dbHandler.h"

@protocol SettingsWindowControllerProtocol<NSObject>
    -(dbHandler*)sendDBobject;
@end

@interface SettingsWindowController : NSWindowController

@property (assign) id<SettingsWindowControllerProtocol> delegate;

@property (retain) dbHandler* dbh;

@end

SettingsWindowController.m:

- (void)windowDidLoad
{
    dbh = [delegate sendDBobject];
    [super windowDidLoad];
    NSLog(@"settings string returned: %@",[dbh returnString]);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It looks like you've made some bad design choices in your application. Not only are you calling down to the app delegate to get the dbh, but you also seem to have a method there that responds to an action message (settingsButton:). Generally, the app delegate is there to be the application's delegate - responding to delegate methods. It's a sign of an inexperienced developer when it does more than that; I frequently see new developers use the app delegate as a convenient singleton object where they can stash data or methods instead of doing it in a more object oriented fashion.

It doesn't help that the Xcode application template initialises the Core Data Stack in the AppDelegate, and many tutorials use the delegate as storage because it keeps the project focussed on the subject of the tutorial rather than increasing complexity by doing things the way they would be done in the real world.

Remember, you want the delegate to do as little as possible. So let the app delegate set up the bare minimum number of objects, hook them up together and get out of the way.

In your case I see two things that you could be doing better. Rather than setting up a protocol to call down to your app delegate to get an object, just send it up the stack to the view controller. And secondly, you have an action method in your application delegate which would be better off in a view controller instead. Since I don't want to get too much into the second, and as your question is about sharing objects; here's how to pass the object up the stack without using a protocol.

in AppDelegate.m

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // This is okay, although it's preferable to be explicit with properties
    self.dbh = [[dbHandler alloc] init];
    ... 
}

- (IBAction)settingsButton:(id)sender {
    if(!self.settingsWindowController){
        self.settingsWindowController = [[SettingsWindowController alloc] initWithWindowNibName:@"SettingsWindow"];

        // It already has a property for the dbh, just give it to it
        self.settingsWindowController.dbh = self.dbh;
    }

    [self.settingsWindowController showWindow:self];
    self.settingsWindowController.delegate = self;
}

// And you don't need this, or the protocol
//-(dbHandler*)sendDBobject{
//    return dbh;
//}

Why is this better? There is a principle of "tell, don't ask". In this case you are telling the settings view controller what the dbh is, not making it ask some other object. Also, you are no longer coupled to an App delegate which conforms to a protocol, which means the controller is less coupled to other objects in your app. Imagine you were to unit test your settings view controller, it's so much easier to just give it the object it wants, rather than setting up the infrastructure for it to ask for things.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...