2013-02-13 22 views
7

任何想法在resume(用户界面保存)目的窗口中存档NSViewController的最佳做法是什么?我尝试将它归档到窗口控制器的encodeRestorableStateWithCoder:方法中,以仅在调用restoreStateWithCoder:时才能发现视图控制器未被取消存档。为Lion的用户界面恢复功能编码NSViewController

// 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对象向下将导致压缩文件名冲突。

在此先感谢!

+0

它可能正在使用安全编码,您是否尝试过使用'-decodeObjectOfClass:forKey:'来代替? – Pol 2015-02-20 20:25:47

回答

5

国家修复工程免费NSView但即使它实现方法为NSResponder一个子类上NSViewController被忽略。我想这是因为窗口不知道可能拥有它包含的一些视图的NSViewController。

在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 

现在,您可以拨打-invalidateRestorableStateNSViewController子和可可,认为它正在同一家NSView,会自动调用-encodeRestorableStateWithCoder:-restoreStateWithCoder:根据您的NSViewController子类。

+0

嗨,这是一个很好的诀窍:)我试图在Mac应用程序上实现恢复,并且即使对于NSView子类,我也没有收到恢复调用。任何想法可能是什么?我为此创建了一个新线程:http://stackoverflow.com/q/42010026/3251155 – 2017-02-02 19:09:05

0

我还没有可恢复状态多乱七八糟(乔纳森·马这样做是为了DL3),但如果我这样做我会尝试删除这两种方法并实现+ restorableStateKeyPaths,如:

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

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

+ (NSArray *)restorableStateKeyPaths; 

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

+0

如果'contentViewController'是窗口控制器的相同类(因此具有相同的可恢复属性集),则这将工作。不幸的是,视图控制器可以在很多类中交换。根据您在左侧“标签”栏中选择的内容,考虑可交换视图的官方Twitter应用。同样,视图控制器也可以根据它们控制的顶层视图进行交换。 – adib 2014-01-16 04:22:35