2

ビューコントローラーの通常のinitメッセージを使用してビューを割り当てると、作成されたビューは私のビューではありませんが、デフォルトのNIB名を使用すると機能します。

具体的には、このコードは常に機能します。nib ファイルで定義されたビューを作成し、parentView に表示します。

+ (void)createTransparentViewCenteredInView:(NSView*)parentView withText:(NSString*)text duration:(NSTimeInterval)duration {
    TransparentAccessoryViewController* controller = [[TransparentAccessoryViewController alloc] initWithNibName:@"TransparentAccessoryViewController" bundle:nil];

    NSLog(@"%@", [controller.view class]);    // Returns "TransparentAccessoryView" -- CORRECT
    [parentView addSubview:controller.view];
}

ただし、次のコードは時々機能します (常に失敗するとは限らないという点で奇妙です)。一部のparentViewでは、完全に正常に機能し、他のものでは機能しません。親ビューはランダムなカスタム NSView です。

+ (void)createTransparentViewCenteredInView:(NSView*)parentView withText:(NSString*)text duration:(NSTimeInterval)duration {
    TransparentAccessoryViewController* controller = [TransparentAccessoryViewController new];

    NSLog(@"%@", [controller.view class]);    // Returns "NSSplitView" -- INCORRECT
    [parentView addSubview:controller.view];
}

表示されるエラーは次のとおりです (ここに NSTableView がまったくないため、なぜ NSTableView が表示されるのかわかりません。また、表示される型がNSSplitView):

2013-04-07 21:33:12.384 アクションの更新に接続できませんでした: クラス TransparentAccessoryViewController のターゲットに

2013-04-07 21:33:12.384 アクション remove: をクラス TransparentAccessoryViewController のターゲットに接続できませんでした

2013-04-07 21:33:12.385 *不正な NSTableView データ ソース ()。numberOfRowsInTableView: および tableView:objectValueForTableColumn:row: を実装する必要があります。

NIB ファイルは、TransparentAccessoryView と呼ばれるカスタムのサブクラス化された NSView を定義し、これをファイル所有者のビュー プロパティである標準的なものに接続します (カスタム クラス名を TransparentAccessoryView に変更しただけです)。何が起こっているのかを確認するために NSLog を追加しましたが、何らかの理由で、2 番目のケースでは、ビュー クラス タイプが正しくなく、何らかの理由で NSSplitView であると考えています。ViewController クラスは次のとおりです。

@implementation TransparentAccessoryViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
    }

    return self;
}

- (void)awakeFromNib {
    self.textField.stringValue = @"";
}

+ (void)createTransparentViewCenteredInView:(NSView*)parentView withText:(NSString*)text duration:(NSTimeInterval)duration {
    TransparentAccessoryViewController* controller = [[TransparentAccessoryViewController alloc] initWithNibName:@"TransparentAccessoryViewController" bundle:nil];

    NSLog(@"%@", [controller.view class]);
    [parentView addSubview:controller.view];
}

@end

デフォルトの init メッセージは、viewcontroller にちなんで名付けられた NIB をロードするように viewcontroller をトリガーすると考えました。

この動作がまったく発生している理由を誰かが知っていますか?

4

2 に答える 2

2

ドキュメントから:

nibNameOrNil に nil を渡すと、nibName は nil を返し、loadView は例外をスローします。この場合、view を呼び出す前に setView: を呼び出すか、loadView をオーバーライドする必要があります。

したがって、 を で初期化する場合はNSViewController-initを呼び出し-setView:てビュー コントローラーのビューを設定するか、オーバーライドする必要があります-loadView。後者の場合、UIViewControllerおそらく期待している - のような動作を確実に実装できます --nibNameOrNilが nil の場合、クラスと同じ名前の nib をロードしてみてください。

于 2013-04-08T06:18:24.610 に答える
1

NSViewControllerを呼び出すときinit、NSViewController の実装がinitビュー コントローラーと同じ名前の nib を検索して使用すると想定していると思います。ただし、これはドキュメント化されていない API であるか、少なくともその仮定を裏付けるドキュメントが見つからないようです。コメントに投稿したリンクもドキュメントを引用しておらず、これは文書化されておらず、Apple がいつでもこの実装を変更できることを繰り返しています。

あなたのコードが SDK の将来のバージョンで動作することを保証するために (また、既に望ましくない動作を作成しているため)、この仮定に頼るべきではないと思います。同じ結果を達成するには、この投稿で説明されているように単純にオーバーライドinitします。initWithNibName:bundle:

@implementation MyCustomViewController

// This is now the designated initializer
- (id)init
{
    NSString *nibName = @"MyCustomViewController";
    NSBundle *bundle = nil;
    self = [super initWithNibName:nibName bundle:bundle];
    if (self) {
        ...
    }
    return self;
}

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
    // Disregard parameters - nib name is an implementation detail
    return [self init];
}
于 2013-04-08T06:04:12.537 に答える