Objective-C实例中的常规初始化序列(例如在指定的初始化程序中)如下:
- (id)initWithFrame: (NSRect)frame {
self = [super initWithFrame: frame];
if (self != nil) {
// Do your stuff.
}
return self;
}
这是一个众所周知的模式,但是真的有必要测试是否分配了自我?我的意思是,如果在super方法中出现问题,那么它不会引发异常而不仅仅是返回nil吗?这是一种安全的模式吗?如果对super的调用有问题但仍返回(随机)指针会怎么样?
这肯定是一个防御性编程的问题,但对于你知道的案例进行如此多的测试确实看起来确实没有任何结果,这看起来真的很夸张。如果您知道它可以发生(当然必须记录在案),那么检查 self 当然是很有意义的。
答案 0 :(得分:3)
当出现问题时,在Objective-c程序中引发异常并不是合理的行为。抛出异常应该仅用于关键的,不可恢复的,程序员错误情况。
从init方法发出错误信号的正确方法是返回nil,并可选择用更多信息填充传递的NSError指针。测试你的超级初始化程序是否返回nil会阻止你进行无用的初始化,并有助于避免可能的崩溃,如:
@implementation {
int _foo; // instance variable
}
- (id)initWithFrame: (NSRect)frame {
self = [super initWithFrame: frame];
if (self != nil) {
_foo = 2;
}
return self;
}
如果超级初始值设定项返回nil,则会崩溃,因为_foo = 2
是self->_foo = 2
的简写,这将取消引用nil指针。 (当self为零时,只有消息发送返回nil;直接访问ivar不能保证。)
答案 1 :(得分:2)
某些类,甚至Apple自己的NS类都可以从初始化程序返回nil
,例如NSArray和NSDictionary的initWithContentsOfFile:
和initWithContentsOfURL:
方法。那些人应该抛出异常吗?没有!它们易于检测并且易于恢复。抛出一个例外对于懒惰的程序员来说只不过是一个拐杖,他们不会为进行适当的错误检查而烦恼,也不会为我们这些做过的人打扰。
答案 2 :(得分:0)
问题归结为:是否有任何(许多)已知类从初始化程序返回nil
?
我认为很少。当然,有一些已知的情况(构造函数通常引用NSError
)必须返回nil
以指出错误。
但是大多数其他初始化器要么返回self
参数,要么返回该类的另一个实例。如果情况并非如此,则应在文档中明确表达,因为代码通常依赖于对象创建而不会失败。
所以我认为在检查超类的行为时省略nil
的测试是完全安全的。
另一方面,这种模式是无所不在的,共同开发者可能会对遗漏感到困惑,并可能将其视为疏忽。因此,如果你计划在没有条件的情况下切换到一种风格,它至少应该以某种方式传达给你的开发者。