NSViewControllerは、メモリ管理に関して、またはトップレベルのオブジェクトに関してさえ、まったく特別なことは何もしません。これは、ペン先をロードし、その内容をペン先のライフサイクルの間メモリに保持するための安全な場所を提供するだけです。つまり、クラス自体は外部のファイルの所有者にすぎません。キックのためだけに、クラスを再実装し、興味深い部分をコメントアウトしました。いくつかのものは、実装する価値がないほどハッキーだったため、または再作成する必要がないほど未使用だったため、完全に削除しました。ドキュメントとコメントを含む完全なクラスは、ここにあります;
@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を操作する機能であり、その基盤となるCoreDataはまともです。
ビューコントローラがnibの「ファイルの所有者」である場合、代わりに、現在のクラスからビューコントローラに参照サイクルをプッシュするだけではありませんか?NSViewControllerはそれを防ぐために何をしますか?
NSViewControllerは、これまでに見た中で最も興味深い方法の1つで、トップレベルオブジェクトの保持を処理します。それらを含む配列への参照を取得すると、配列のシャローコピーが作成され-release
、古い配列のすべてのオブジェクトが作成されます。事実上、NSViewControllerは、NIBの解凍されたオブジェクトへのすべての参照をNSCoderから奪い取り、配列がでなくなったときに安全に解放されることを保証し-dealloc
ます。
NSAutounbinder
ただし、バインディングに関しては、NSViewControllerには、オブジェクトをバインドおよびバインド解除するときにKVOが検索するという名前のNSProxyサブクラスの内部ゲッターがあります。リリースを微調整し、内部の自動アンバインダーポインターにゲッターを提供することで、コントローラークラスは自分自身とそのバインディングを争うことなく解放できます。KVOが自動アンバインダーゲッターを探していることを確認せずに、将来のOS XリリースでCFIViewControllerの実装を使用することは絶対にお勧めしませんが、他のほとんどのリリースでは問題ないようです。CFIViewControllerは、最新のコミットの時点で内部NSAutoUnbinderクラスを使用するオプションを提供します。これにより、バインディング保持サイクルを解決します。