对于内存管理甚至顶级对象,NSViewController没有什么特别之处。它只是提供一个安全的地方来加载一个笔尖,然后将其内容保存在笔记本生命周期的内存中,这意味着该类本身不过是外部文件的所有者。为了踢球,我重新实施了这个课程,并且评论了一些有趣的部分。有些东西,我只是彻底删除,因为它太冒险了,不值得实施,或者没有使用,以至于无法重新制作。完整的课程,包括文档和评论,可以找到here;
@interface CFIViewController : NSResponder <NSCoding> {
@private
NSString *_nibName;
NSBundle *_nibBundle;
id _representedObject;
NSString *_title;
IBOutlet NSView *view;
NSArray *_topLevelObjects;
id _autounbinder;
//NSString *_designNibBundleIdentifier;
}
- (id)initWithNibName:(NSString*)nibName bundle:(NSBundle *)nibBundleOrNil;
- (void)setRepresentedObject:(id)representedObject;
- (id)representedObject;
- (void)setTitle:(NSString *)title;
- (NSString *)title;
- (NSView *)view;
- (void)loadView;
- (NSString *)nibName;
- (NSBundle *)nibBundle;
- (void)setView:(NSView *)view;
@end
@implementation CFIViewController
- (void)loadView {
NSArray *topLevelObjects = nil;
NSNib *loadedNib = [[[NSNib alloc]initWithNibNamed:self.nibName bundle:self.nibBundle]autorelease];
if (loadedNib == nil) {
[NSException raise:NSInternalInconsistencyException format:@"-[%@ %@]", NSStringFromClass(self.class), NSStringFromSelector(_cmd)];
return;
}
BOOL loaded = NO;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
loaded = [loadedNib instantiateWithOwner:self topLevelObjects:&topLevelObjects];
#else
loaded = [loadedNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjects];
#endif
if (loaded) {
[self _setTopLevelObjects:topLevelObjects];
[topLevelObjects makeObjectsPerformSelector:@selector(release)];
} else {
[NSException raise:NSInternalInconsistencyException format:@"CFIViewController could not instantiate the %@ nib.", self.nibName];
}
if (self.view != nil) {
[self viewDidLoad];
return;
}
[NSException raise:NSInternalInconsistencyException format:@"-[%@ %@]", NSStringFromClass(self.class), NSStringFromSelector(_cmd)];
}
@end
这确实是一个相当简单的机制。所有的NSViewController真的增加了Cocoa中的任何一种控制器隐喻,就是能够使用NSDocument以及它的基础Core Data混乱。
如果视图控制器是笔尖的“文件的所有者”不是我,而只是将参考周期从我的当前类推到我的视图控制器? NSViewController做什么来防止这种情况?
NSViewController以我见过的最有趣的方式之一处理顶层对象的保留。当它获得对包含它们的数组的引用时,它将对该数组进行浅度复制,然后对所有旧数组的对象进行浅度复制。实际上,NSViewController会将对NIB的除霜对象的每个引用都从NSCoder中取出,从而在数组在-dealloc
中消失时保证安全释放。
但是,当涉及到绑定时,NSViewController有一个名为NSAutounbinder
的NSProxy子类的内部getter,KVO会在绑定和解除绑定对象时寻找它。通过调整释放并为内部自动绑定器指针提供一个getter,控制器类可以释放自身和绑定,而不会打架。绝对不建议您在未来的OS X版本中使用CFIViewController中的实现,而不验证KVO仍然在寻找autounbinder getter,但对于大多数其他版本,似乎没有问题。 CFIViewController提供了在最新的提交时使用内部NSAutoUnbinder类的选项,从而解决了任何绑定都会保留周期的问题。
这真的比我预料的任何人都付出了更多的努力!谢谢你,我会研究它。当有奖金时,我会给你一些额外的奖励。 – dreamlax 2013-03-27 23:17:38
@dreamlax谢谢你!我真的很喜欢偷看AppKit的内部并使它更易于管理。随意在今后的任何项目中使用它。 – CodaFi 2013-03-27 23:18:17
如果我现在接受你的答案,赏金选项就会消失,所以我暂时不接受它(但不用担心我会回来!) – dreamlax 2013-03-27 23:36:10