为 Lion 的用户界面恢复功能编码 NSViewController
Posted
技术标签:
【中文标题】为 Lion 的用户界面恢复功能编码 NSViewController【英文标题】:Encoding NSViewController for Lion's user interface resume feature 【发布时间】:2013-02-13 01:25:05 【问题描述】:知道将NSViewController
归档在窗口内以用于resume(用户界面保留)目的的最佳做法是什么?我尝试在窗口控制器的 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
对象将导致存档中的名称冲突。
提前致谢!
【问题讨论】:
它可能使用了安全编码,你试过-decodeObjectOfClass:forKey:
吗?
【参考方案1】:
状态恢复在NSView
上免费工作,但在NSViewController
上被忽略,即使它将方法实现为NSResponder
的子类。我想这是因为窗口不知道可能拥有它包含的某些视图的 NSViewControllers。
在 OS X Yosemite 上它应该可以工作,因为 NSWindow
现在真正支持 NSViewControllers,但在我的测试用例中没有。我想这是因为人们需要使用新的 API 来“链接” NSViewController 来添加/删除它们,而不是在一边创建它们,然后直接将它们的视图添加到窗口中。如果您想让您的应用在优胜美地之前的系统上运行,则实际上需要后者。
以下是让它始终工作的方法:只需代理 NSView
和 NSViewController
之间的恢复 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
现在您可以从 NSViewController
子类调用 -invalidateRestorableState
,而 Cocoa 认为它正在与 NSView
对话,会根据需要在您的 NSViewController
子类上自动调用 -encodeRestorableStateWithCoder:
和 -restoreStateWithCoder:
。
【讨论】:
嗨,这是一个不错的技巧 :) 我也在尝试在 Mac 应用程序上实现恢复,即使是 NSView 子类我也没有收到恢复调用。知道那可能是什么吗?我为此创建了一个新线程:***.com/q/42010026/3251155【参考方案2】:我对可恢复状态的处理并不多(Jonathon Mah 是为 DL3 做的),但如果我这样做,我会尝试删除这两个方法并实现 +restorableStateKeyPaths,例如:
+ (NSArray *)restorableStateKeyPaths;
return @[@“contentViewController.firstInterestingStateProperty”, @“contentViewController.secondInterestingStateProperty”];
然后看看机器是否为我处理了这一切。
+ (NSArray *)restorableStateKeyPaths;
返回一组关键路径,表示属性的路径 应该是持久的。框架将通过以下方式观察这些关键路径 KVO 并自动将其值持久化为持久化的一部分 状态,并在重新启动时恢复它们。关键路径的值 应实施密钥归档。基本实现返回一个 空数组。
【讨论】:
如果contentViewController
是窗口控制器的同一个类(因此具有相同的可恢复属性集),这将起作用。不幸的是,视图控制器可以在很多类之间交换。想想官方 Twitter 应用程序,根据您在左侧“选项卡”栏中选择的内容,可交换视图。同样,视图控制器也可以根据它们控制的***视图进行交换。以上是关于为 Lion 的用户界面恢复功能编码 NSViewController的主要内容,如果未能解决你的问题,请参考以下文章
iOS 5/Lion Core Data 有序关系:指定顺序?