0

我感觉很愚蠢,但是......在自定义类型中初始化实例变量的正确方法是什么,派生自 Cocoa Touch UI 类?

假设我有类型,源自UIViewController,让它成为TRUIController。我定义了一个 ivar,如下所示:

@implementation TRUIController
{
    NSNumberFormatter *_numberFormatter;
}
@end

我应该把_numberFormatter初始化代码放在哪里,如果我希望它在任何 UI 方法之前执行viewDidLoad,等等?

在其他语言中,我会创建constructor、调用base constructor然后初始化我的 ivars。但这根本不适用于objective-cand Cocoa Touch

在上述情况下,如果我写

-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibBundleOrNil bundle:nibBundleOrNil];
    if(self)
    {
        //init ivars
    }
    return self;
}

不行,我再试试别的initWithBlaBla方法,最后find init其实就是调用的,那样的话——initWithCoder:

现在,假设我有从 UITableViewCell 派生的类。同样,需要初始化NSNumberFormatterivar。为什么我不能只覆盖init:、调用super和初始化我的 ivars?

这个奇怪的设计决定背后的想法是什么?没有为所有类型提供单一的通用初始化方法?

它是在派生类型中初始化 ivars 的唯一方法吗?每次都做一些研究来弄清楚这次覆盖什么方法?

我错过了什么吗?因为感觉非常愚蠢/不直观/容易出错

4

2 回答 2

2

您必须这样做覆盖指定的初始化程序。

来自官方文档

指定初始化程序是调用超类的 init 方法的类的 init 方法。(其他初始化程序调用该类定义的 init 方法。)每个公共类都应该有一个或多个指定的初始化程序。作为指定初始化器的示例,有 NSView 的 initWithFrame: 和 NSResponder 的 init 方法。在 init 方法不打算被覆盖的情况下,就像 NSString 和其他面向类集群的抽象类的情况一样,子类应该实现自己的。

指定的初始化程序应该明确标识,因为这些信息对于那些想要继承你的类的人来说很重要。子类可以只覆盖指定的初始化程序,所有其他初始化程序将按设计工作。

当您实现一个框架类时,您通常还必须实现它的归档方法:initWithCoder: 和 encodeWithCoder:。小心不要在初始化代码路径中做对象未归档时不会发生的事情。实现此目的的一个好方法是,如果您的类实现归档,则从您指定的初始化程序和 initWithCoder: (它本身就是一个指定的初始化程序)调用一个通用例程。

阅读文档以找出指定的初始化程序并覆盖它。

根据文档 UIViewController initWithNibName:bundle:是此类的指定初始化程序,因此您应该覆盖该初始化程序,但是如果您没有以编程方式实例化您的类(例如,您从 nib/storyboard 加载它),则必须覆盖归档方法initWithCoder:

正如文档所建议的,您可以创建一个用于初始化的例程,并从指定的初始化程序和归档方法中调用它。

于 2013-01-23T19:27:21.577 回答
1

使用指定的初始值设定项作为起点通常是有意义的,但如果您不确定这是否始终是将要使用的初始值设定项,那将没有多大意义。

因此,我个人更喜欢创建一个 setup 方法,该方法从我知道可能在某个阶段使用的任何 init 方法调用。对于 ViewController,我通常从 viewDidLoad 调用 setup 方法(当然,除非在此阶段之前需要任何状态)。

于 2013-01-23T19:29:32.693 回答