3

我正在设置 OSX 开发的第一步,但遇到了一些问题。我有相当多的 iOS 开发经验,但 OSX 程序的窗口系统是另一回事。

我正在为 twitter 之类的社交网络创建一个客户端,需要 2 个单独的窗口控制器来首次启动应用程序,如果您已登录则显示您的时间线,如果您尚未登录,则需要一个用于登录。在信息中.plist 你需要给它一个 main.xib。为此,我做了一个空的 xib,我在应用程序启动的第二个地方隐藏了它。这不是一个很好的解决方案IMO,有什么更好的解决方案?我想让窗口与 appdelegate 分开,因为这样我可以让我的代码分开。

这给了我一个问题,当我打开“第二个”窗口进行登录时,它会显示但未激活。我已经尝试了所有的东西,比如 orderFront:、activateIgnoringOtherApps:、makeKeyAndOrderFront: 等等。但这一切都行不通。。

所以:首先,是否有更好的方法来处理 info.plist 中所需的 main.xib,如果没有,是否有解决焦点问题的方法?我正在使用 osx 10.7

4

2 回答 2

2

不止一次,您真的应该将您的应用程序委托与您的窗口控制器分开。继续并从模板创建一个新的 Cocoa 应用程序。在MainMenu.xib中,删除窗口。在AppDelegate.h删除IBOutletNSWindow. 用s--perhaps和.创建几个新的NSWindowControllercomplete子类。 XIBLoginWindowControllerTimelineWindowController

对于“最终”NSWindowController子类(即那些不会被子类化的子类),指定初始化器的最佳实践是

//for our example class LoginWindowController
- (id)init
{
    self = [super initWithWindowNibName:@"LoginWindowController"];
    if (self) {
        //....
    }
    return self;
}

现在在您的应用程序委托中,您应该拥有@properties两个不同的窗口控制器实例:

//Within AppDelegate.m

#import "AppDelegate.h"
#import "LoginWindowController.h"
#import "TimelineWindowController.h"

@interface AppDelegate ()
@property (nonatomic) LoginWindowController *loginWindowController;
@property (nonatomic) TimelineWindowController *timelineWindowController;
//For the sake of this demo, add a property for the loggedIn state:
@property (nonatomic) BOOL loggedIn;
@end

你应该在你的应用程序委托中有某种方法来呈现正确的窗口控制器。让我们称之为-updateWindowVisibility

- (void)updateWindowVisibility
{
    BOOL isLoggedIn = self.loggedIn;

    BOOL loginWindowVisible = self.loginWindowController.window.isVisible;
    BOOL showLoginWindow = !isLoggedIn;

    BOOL timelineWindowVisible = self.timelineWindowController.window.isVisible;
    BOOL showTimelineWindow = isLoggedIn;

    if (!loginWindowVisible && showLoginWindow) {
        if (!self.loginWindowController) self.loginWindowController = [[LoginWindowController alloc] init];
        [self.loginWindowController showWindow:nil];
    } else if (loginWindowVisible && !showLoginWindow) {
        [self.loginWindowController close];
        self.loginWindowController = nil;
    }

    if (!timelineWindowVisible && showTimelineWindow) {
        if (!self.timelineWindowController) self.timelineWindowController = [[TimelineWindowController alloc] init];
        [self.timelineWindowController showWindow:nil];
    } else if (timelineWindowVisible && !showTimelineWindow) {
        [self.timelineWindowController close];
        self.timelineWindowController = nil;
    }
}

上面实现的这种方法比当前设置所需的工作要多一点,但是当您需要显示/隐藏其他窗口时应该更容易修改。此时剩下要做的就是调用-updateWindowVisibilityfrom -applicationDidFinishLaunching:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.isLoggedIn = NO;
    [self updateWindowVisibility];
}

我已经在github上发布了一个示例应用程序来演示这种方法。

于 2012-10-30T17:01:04.603 回答
1

在结构方面(你的第一个问题),我会推荐这个:

  1. 创建一个带有一个空白窗口和一个覆盖它的大 NSView(例如,称为 megaView)的 XIB。在 AppDelegate 中为您的大 NSView 创建一个 IBOutlet。将应用设置为在加载时使用此 XIB。
  2. 创建两个单独的 NSView XIB:一个用于登录状态,一个用于注销状态。把你的布局放在这些里面。
  3. 创建两个 NSViewController 子类:一个控制您刚刚创建的每个 NSView 的逻辑。我们称它们为LoggedOutViewControllerLoggedInViewController
  4. 跳回您创建的两个 NSView。将登录的 NSView 的文件所有者设置为 LoggedInViewController,将注销的 NSView 的文件所有者设置为 LoggedOutViewController。将每个文件所有者的视图(右键单击文件所有者以找到它)连接到相应的 NSView。
  5. 在您的应用委托中,以您需要的任何方式确定用户的身份验证状态。

如果已登录,请执行以下操作:

NSViewController *loggedInController = [[NSViewController alloc] initWithNibName:@"NibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedInController view]];

否则,使用您的 loggedOutController 执行上述过程:

NSViewController *loggedOutController = [[NSViewController alloc] initWithNibName:@"OtherNibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedOutController view]];

这应该会让你得到你想要的,并且可能会在这个过程中解决你的第二个问题。我的答案和 Nate 的不同之处在于我使用了相同的窗口。有条件地实例化视图控制器并将它们的视图加载到超级视图中可能是我学到的 Cocoa 中最重要的方面。

于 2012-10-30T16:54:47.317 回答