6

我已经使用 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.

不过,这似乎相当混乱。这一切都只是为了初始化一个对象。其他人如何做到这一点?

4

3 回答 3

9

每个类都应该有一个指定的初始化器;必须始终调用以正确初始化类的一种真正的init...方法变体(如马特所述)。

但是,这并不能完全解决问题,因为一个类也可能支持通过取消归档进行实例化,这会在您的问题中遇到相同的“我在哪里放置常见的初始化 goop”问题。

通常,我创建一个方法,如:

- (void)commonInit
{
     ... common initialization goop goes here ...
}

然后首先从指定的初始化程序和/或initWithCoder:.

是的,有点乱,但你无能为力。

减少混乱的一般策略:

• 提供非常少的初始化器;可能init+ 一个初始化器,其中包含其他配置的所有可能参数。

• 将super的初始化程序指定为您的 DI,并通过它调用任何其他初始化程序。当子类化你有一个更具体的 DI(参见UIView's initWithFrame:)时,覆盖 super 的 DI 以调用[self initFancy:...]然后调用[super initThroughSupersDI].

于 2013-08-12T16:11:11.163 回答
8

您缺少指定初始化程序的概念。您编写了一个 init 方法来完成繁重的工作。所有其他初始化程序只是调用指定的初始化程序。您的示例如下所示:

-(id)init {
    return [self initWithFrame:CGRectZero];
}

-(id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor yellowColor];
    }
    return self;
}
于 2013-08-12T16:09:00.173 回答
1

…每次都附加类名,例如-initialSetupTextField

是的,正是如此,或者您可以为您的私有实例初始化例程创建一个 C 函数——当指定的初始化程序不足时。我使用与您不同的命名方案,但只要您使用避免冲突的约定,那么您就很好。我之所以提到这一点,是因为您的示例中的方法可能会与 getter 混淆。

我要做的另一件事是从该例程返回一个值,该值指示是否存在错误(即nil应该返回)。

于 2013-08-12T18:43:53.273 回答