Objective c 在两个类之间共享对象

Objective c 在两个类之间共享对象,objective-c,cocoa,Objective C,Cocoa,我正在为OSX开发一个应用程序,我遇到了一个问题 应用程序的结构是: AppDelegate:从MainMenu.xib执行主要操作的位置。它也是创建主窗口的地方 SettingsWindowController:其中使用SettingsWindowController.xib中的接口定义设置窗口 我创建了一个协议设置SwindowProtocol来委托这两个类 我又创建了一个类dbHandler,它在AppDelegate中初始化为objdbh 在SettingsWindowProtocol

我正在为OSX开发一个应用程序,我遇到了一个问题

应用程序的结构是:

  • AppDelegate:从MainMenu.xib执行主要操作的位置。它也是创建主窗口的地方

  • SettingsWindowController:其中使用SettingsWindowController.xib中的接口定义设置窗口

  • 我创建了一个协议设置SwindowProtocol来委托这两个类

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

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

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

与问题相关的几段代码:

AppDelegate.h:

#import "dbHandler.h"    

...

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

-(dbHandler*)sendDBobject;
设置SwindowController.h:

#import "dbHandler.h"

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

@interface SettingsWindowController : NSWindowController

@property (assign) id<SettingsWindowControllerProtocol> delegate;

@property (retain) dbHandler* dbh;

@end

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

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

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

Xcode应用程序模板初始化AppDelegate中的核心数据堆栈并没有什么帮助,许多教程都将委托用作存储,因为它使项目集中于教程的主题,而不是像在现实世界中那样做,从而增加复杂性

请记住,您希望代理尽可能少地执行操作。因此,让应用程序代理设置最小数量的对象,将它们连接在一起,然后让开

在你的情况下,我看到两件事你可以做得更好。与其设置一个协议来调用你的应用程序代理来获取一个对象,不如将它向上发送到视图控制器。其次,在应用程序委托中有一个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;
//}

为什么这样更好?有一个原则是“说,不要问”。在本例中,您告诉设置视图控制器dbh是什么,而不是让它询问其他对象。此外,您不再与符合协议的应用程序委托耦合,这意味着控制器与应用程序中的其他对象耦合更少。假设您要对设置视图控制器进行单元测试,只给它想要的对象比为它设置基础设施来请求东西要容易得多。

很好的洞察力,但请使用
NSApp
,因为这是OS X而不是iOS.Hm,感谢您的快速重播。但我是为osX开发的,所以我没有使用UIApplication,而是使用了如下NSApplication:AppDelegate*AppDelegate=[[NSApplication sharedApplication]delegate];dbh=appDelegate.dbh;我得到了一个警告:用一个不兼容类型“id”的表达式初始化“AppDelegate*_strong”@Mazyod谢谢你指出这一点。已经更新了答案。哦,很好,现在可以工作了,但是你能解释一下为什么以这种方式工作,并且抛出协议中的方法不工作吗?如果dbHandler的初始化不在AppDelegate@user1792771协议只是定义了一个共享接口,符合该协议的对象需要实现该接口。它不会以某种方式让您全局访问符合协议的其他对象中的任何属性。如果您想从应用程序委托以外的其他位置初始化dbHandler,您可以这样做,但我仍然建议将结果存储在应用程序委托中,因为这是一个始终易于从应用程序中的其他位置访问的对象。因此,我想关键优势在于将其他对象与应用程序委托分离。我感谢你花时间提供如此详细的解释。谢谢。这也是我们在导航控制器和故事板序列中已经看到的一种模式->信息通过属性向上传递,信息和动作通过委托协议向下传递。当然,但我更感兴趣的是这种模式的具体优势,而不仅仅是为了一致性而遵循这种模式。我并不认为从众是件坏事,但当你不理解其背后的原因时,这只会鼓励货运狂热编程。我刚刚看到你的回应,感谢你的解释。你是对的,我在objective C和oop方面都是新的程序员,但我正在努力学习。因此,为了确保我正确理解这一点,您的意思是最好不要将AppDelegate用作应用程序的主类。我应该在AppDelegate中创建新类并在它们之间建立连接。而且我不应该从我应该发送的类中获取对象。这听起来像iPhone中的segues,对吧?这看起来和OSx中没有segues的原理是一样的。segues是一个向上发送引用到您创建的对象,并使用委派和协议向下与父对象通信的示例。这一原则才是重要的,而不是分段。
AppDelegate *appDelegate = [NSApp delegate];
dbh = appDelegate.dbh;
- (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;
//}