我想为UIViewController
构建一个自定义的init方法,但是在浏览互联网之后,特别是在SO中我对指定的初始化器感到困惑。
我有一个UIViewController
的子类,带有这两个初始化器:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if ( self ) {
}
return self;
}
- (id) initWithFilename:(NSString *)aFilename {
self = [self initWithNibName:@"WallpaperDetailsViewController" bundle:nil];
if ( self ) {
self.filename = aFilename;
}
return self;
}
然后我有一个viewDidLoad
方法根据filename
属性自定义视图:
- (void)viewDidLoad {
[super viewDidLoad];
// Create a UIImageView to display the wallpaper
self.wallpaper = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.filename]];
// ...
}
在另一个UIViewController
中,我拨打以下电话:
WallpaperDetailsViewController *detailsViewController = [[WallpaperDetailsViewController alloc] initWithFilename:@"foobar.png"];
[[self navigationController] pushViewController:detailsViewController animated:YES];
结果是viewDidLoad
由于[self initWithNibName:]
而被调用,UIImageView
未初始化self.filename
,因为viewDidLoad:
为空。
根据其他SO问题和答案,这应该是预期的行为。我不确定这是因为我自己在iOS 5之前的其他项目中的经验。我的问题是:
如何确保在initWithFilename:
后调用initWithFilename:
,而不是在initWithNibNameOrNil:bundle:
和{{1}}之间调用?
如果不可能,我如何实现接收自定义数据的初始化方法来创建和自定义视图?
谢谢!
答案 0 :(得分:2)
我找到了问题。
WallpaperDetailsViewController
不会直接从UIViewController
继承,而是从我已实施的其他自定义UIViewController
继承。
问题是什么?我已经在父initWithNibName
方法中初始化了子视图,而不是遵循延迟加载技术并在viewDidLoad
中执行。当WallpaperDetailsViewController
调用其父初始值设定项时,它会变得混乱并导致viewDidLoad
无法正常运行。
解决方案?我将父类中的每个子视图初始化移动到其viewDidLoad
方法,并使WallpaperDetailsViewController
的原始实现保持不变。现在一切都按预期工作了
感谢@Josh Caswell和@logancautrell
答案 1 :(得分:1)
您不需要initWithNibName:bundle:
的空实现。此外,看起来你的类正在建立它的指定初始化器为initWithFilename:
如果这是真的,initWithFilename:
应该调用超类的D.I。:
- (id) initWithFilename:(NSString *)aFilename {
// Call super's designated initializer
self = [super initWithNibName:@"WallpaperDetailsViewController"
bundle:nil];
if ( self ) {
self.filename = aFilename;
}
return self;
}
规则是类中的所有初始值设定项应该调用类的D.I.和D.I.本身应该调用超类的D.I。
在初始化程序完成之前,您发布loadView:
的原因并不完全清楚。 Logancautrell的评论建议在视图加载方法中设置断点是好的。
答案 2 :(得分:0)
为什么不在每次设置文件名时使用自定义setter来初始化UIImage的filename属性?
或者,或者在viewWillAppear中设置文件名属性的UIImage:而不是viewDidLoad。
答案 3 :(得分:0)
首先,建议您不要在初始化程序中使用点语法。有关一些好的讨论,请参阅以下内容:
Objective-C Dot Syntax and Init
其次,您可以做的是在初始化程序中分配图像。所以你可以按照
的方式做点什么- (id) initWithFilename:(NSString *)aFilename {
self = [self initWithNibName:@"WallpaperDetailsViewController" bundle:nil];
if ( self ) {
filename = [aFilename retain];
wallpaper = [[UIImageView alloc] initWithImage:[UIImage imageNamed:aFileName]];
}
return self;
}
这将允许您在调用viewDidLoad之前完成所有设置并保持良好状态。
祝你好运!