在两个类之间共享对象

时间:2013-06-24 21:17:20

标签: objective-c cocoa

我正在为OS X开发一个应用程序,但我遇到了问题。

应用程序的结构是:

  • AppDelegate:主要操作发生在MainMenu.xib中。它也是创建主窗口的地方。

  • SettingsWindowController:使用SettingsWindow.xib中的界面定义设置窗口。

  • 我创建了一个协议SettingsWindowProtocol来委派这两个类。

  • 我又创建了一个类dbHandler,在AppDelegate中初始化为obj dbh

  • 在SettingsWindowProtocol中,我创建了一个发送对象的方法,但在SettingsWindowControl中调用此方法后,该对象为空。

问题是我如何在两个不同的类中共享同一个对象?

与问题相关的几段代码:

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]);
}

2 个答案:

答案 0 :(得分:1)

看起来您在应用程序中做了一些糟糕的设计选择。你不仅要调用app委托来获取dbh,而且你似乎还有一个响应动作消息的方法(settingsButton:)。通常,应用程序委托是应用程序的委托 - 响应委托方法。这是一个没有经验的开发人员的标志,当它做的不止于此时;我经常看到新的开发人员使用app delegate作为一个方便的单例对象,他们可以存储数据或方法,而不是以更面向对象的方式进行。

Xcode应用程序模板初始化AppDelegate中的核心数据堆栈并没有帮助,许多教程使用委托作为存储,因为它使项目专注于教程的主题,而不是通过执行来增加复杂性事物就像在现实世界中完成的那样。

请记住,您希望代表尽可能少地做。因此,让app delegate设置最少数量的对象,将它们连接在一起然后放弃。

在你的情况下,我看到你可以做得更好的两件事。而不是设置一个协议来调用你的应用程序委托来获取一个对象,而只是将它发送到堆栈的视图控制器。其次,您在应用程序委托中有一个action方法,而在视图控制器中则更好。因为我不想过多地进入第二个,因为你的问题是关于共享对象;这里是如何在不使用协议的情况下将对象传递到堆栈中。

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;
//}

为什么这样更好?有一个原则是&#34;告诉,不要问&#34;。在这种情况下,您告诉设置视图控制器dbh是什么,而不是让它询问其他对象。此外,您不再耦合到符合协议的App委托,这意味着控制器与应用程序中的其他对象的耦合较少。想象一下,你要对你的设置视图控制器进行单元测试,它只是给它想要的对象更容易,而不是为它设置基础设施来询问事物。

答案 1 :(得分:0)

您可以通过NSApp delegate方法从应用中的任意位置访问您的应用代理。因此,要获得dbh对象,您只需执行以下操作:

AppDelegate *appDelegate = [NSApp delegate];
dbh = appDelegate.dbh;