为Lion的用户界面恢复功能编码NSViewController

时间:2013-02-13 01:25:05

标签: cocoa osx-lion appkit resume nsarchiving

知道在resume(用户界面保存)目的窗口内归档NSViewController的最佳做法是什么?我尝试在窗口控制器的encodeRestorableStateWithCoder:方法中对其进行归档,但发现在调用restoreStateWithCoder:时视图控制器不会被取消归档。

// NSWindowController subclass

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    [super encodeRestorableStateWithCoder:coder];
    NSViewController* contentViewController = self.contentViewController;
    if (contentViewController) {
        [coder encodeObject:contentViewController forKey:BSContentViewControllerResumeKey];
    }
}

-(void)restoreStateWithCoder:(NSCoder *)coder
{
    [super restoreStateWithCoder:coder];
    NSViewController* contentViewController = [coder decodeObjectForKey:BSContentViewControllerResumeKey];
    if (contentViewController) {
        // somehow this never get executed since contentViewController always comes out nil
        self.contentViewController = contentViewController;
    }
}

请注意,此视图控制器包含管理其自己的子视图的其他视图控制器,因此需要在NSCoder实例中进行一些作用域 - 只需向下传递提供的coder对象将导致名称冲突档案

提前致谢!

2 个答案:

答案 0 :(得分:6)

状态恢复在NSView上免费工作,但在NSViewController上被忽略,即使它将方法实现为NSResponder的子类。我想这是因为窗口不知道NSViewControllers可能拥有它包含的一些视图。

在OS X Yosemite上它应该可以工作,因为NSWindow现在真正支持NSViewControllers,但它不适用于我的测试用例。我想这是因为我们需要使用新API“链接”NSViewControllers来添加/删除它们,而不是在侧面创建它们,只是将它们的视图直接添加到窗口中。如果你想让你的应用程序在Yosemite之前的系统上运行,那么后者实际上是必需的。

以下是如何使其始终有效:只需在NSViewNSViewController之间代理恢复API调用。

子类NSView是这样的:

@interface GIView : NSView
@property(nonatomic, weak) GIViewController* viewController;  // Avoid retain-loops!
@end

@implementation GIView

- (void)setViewController:(GIViewController*)viewController {
  _viewController = viewController;
}

- (void)encodeRestorableStateWithCoder:(NSCoder*)coder {
  [super encodeRestorableStateWithCoder:coder];

  [_viewController encodeRestorableStateWithCoder:coder];
}

- (void)restoreStateWithCoder:(NSCoder*)coder {
  [super restoreStateWithCoder:coder];

  [_viewController restoreStateWithCoder:coder];
}

@end

NSViewController就像这样:

@interface GIViewController : NSViewController
@end

@implementation GIViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
  if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
    self.view.viewController = self;  // This loads the view immediately as a side-effect
  }
  return self;
}

- (void)dealloc {
  self.view.viewController = nil;  // In case someone is still retaining the view
}

- (void)invalidateRestorableState {
  [self.view invalidateRestorableState];
}

@end

现在您可以从-invalidateRestorableState子类和Cocoa调用NSViewController,认为它正在与NSView对话,会自动调用您的-encodeRestorableStateWithCoder:-restoreStateWithCoder: <{1}}根据需要进行子类化。

答案 1 :(得分:0)

我没有多少与可恢复状态混淆(Jonathon Mah为DL3做了它)但是如果我这样做,我会尝试删除这两种方法并实现+ restorableStateKeyPaths,例如:

+ (NSArray *)restorableStateKeyPaths;
{
    return @[@“contentViewController.firstInterestingStateProperty”, @“contentViewController.secondInterestingStateProperty”];
}

看看机器是否为我处理了这一切。

+ (NSArray *)restorableStateKeyPaths;
  

返回一组键路径,表示属性的路径   应该坚持不懈。框架将通过观察这些关键路径   KVO并自动将其值保留为持久性的一部分   状态,并在重新启动时恢复它们。关键路径的值   应该实现密钥存档。基础实现返回一个   空数组。