我已经使用Objective-C几年了,但我仍然不确定如何初始化一个对象。我们的问题是:
-(id)init {
self = [super init];
if (self) {
self.backgroundColor = [UIColor blueColor];
self.textColor = [UIColor greenColor];
}
return self;
}
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor yellowColor];
}
return self;
}
在两种方法中对其进行初始化同样意味着复制和粘贴编码(巨大的禁忌,由于人为错误导致无穷无尽的问题,例如值不同,如上例所示)或新方法:
-(id)init {
self = [super init];
if (self) {
[self initialSetup];
}
return self;
}
-(id)initialSetup {
self.backgroundColor = [UIColor blueColor];
self.textColor = [UIColor greenColor];
}
这就产生了一个问题,即如果子类有initialSetup
方法,则调用[self initialSetup]
的超类将调用子类的initialSetup
,从而忽略所有超类的设置。您可以通过每次附加类名来解决此问题,例如initialSetupTextField
。
但这似乎相当混乱。这只是初始化一个对象。其他人如何做到这一点?
答案 0 :(得分:9)
每个类都应该有一个指定的初始化程序;必须始终调用一个真正的init...
方法变体来正确初始化类(如Matt所述)。
然而,这并没有完全解决这个问题,因为一个类也可能通过unarchival支持实例化,这会在你的问题中遇到同样的“我在哪里放置常见的初始化goop”问题。
通常,我创建一个方法,如:
- (void)commonInit
{
... common initialization goop goes here ...
}
然后从指定的初始化程序和/或initWithCoder:
将其称为 。
是的,有点乱,但你可以做的不多。
减少混乱的一般策略:
•提供非常少的初始化器;也许init
+一个初始化程序,包含其他配置的所有可能参数。
•将super
的初始化程序指定为您的DI,并通过它调用任何其他初始化程序。当你有一个更具体的DI的子类化时(见UIView
的{{1}}),覆盖超级的DI来调用initWithFrame:
然后调用[self initFancy:...]
。
答案 1 :(得分:8)
你错过了Designated Initializer的概念。你编写了一个执行繁重工作的init方法。所有其他初始化程序只调用指定的初始化程序。您的示例如下所示:
-(id)init {
return [self initWithFrame:CGRectZero];
}
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor yellowColor];
}
return self;
}
答案 2 :(得分:1)
...每次都附加班级名称,例如
-initialSetupTextField
是的,正是如此,或者您可以为私有实例初始化例程创建一个C函数 - 当指定的初始化程序不足时。我使用了与你不同的命名方案,但只要你使用避免碰撞的约定,那么你就是好的。我之所以提到这一点,是因为你的例子中的方法可能会混淆吸气剂。
我做的另一件事是从此例程返回一个值,指示是否存在错误(即应返回nil
)。