我在NSViewController中遇到一个奇怪的错误,如果我使用viewcontroller的常规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];
}
但是,以下代码在某些时候起作用(这很奇怪,因为它并不总是失败)。对于一些parentViews,它可以很好地工作,而对于其他的,它没有。父视图只是随机自定义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。而且,它在类型时抱怨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来查看发生了什么,并且由于某种原因,在第二种情况下,视图类类型不正确并且由于某种原因认为它是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加载以viewcontroller命名的NIB,在某些情况下似乎是这种情况,因为我的代码的第二个版本在某些条件下工作。
有谁知道为什么会发生这种行为?
答案 0 :(得分:2)
来自the docs:
如果为nibNameOrNil传入nil,则nibName将返回nil和 loadView将抛出异常;在这种情况下,你必须调用 setView:在调用view之前,或覆盖loadView。
因此,如果您使用NSViewController
初始化-init
,则应调用-setView:
来设置视图控制器的视图,或覆盖-loadView
。在后一种情况下,您当然可以实现您可能期望的类似UIViewController
的行为 - 如果nibNameOrNil
为nil,请尝试加载与该类名称相同的nib。 / p>
答案 1 :(得分:1)
我认为当你在NSViewController上调用init
时,你假设NSViewController的init
实现搜索一个与视图控制器同名的nib并使用它。但是,这是未记录的API,或者至少我似乎无法找到任何支持该假设的文档。您在评论中发布的link也没有引用任何文档,甚至重申这是没有文档记录的,并且Apple可以随时更改此实现。
我认为确保您的代码在SDK的未来版本中有效(并且因为它已经在创建不需要的行为),所以您不应该依赖这个假设。要获得相同的结果,只需按this post所述的方式覆盖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];
}