Objective-C - 调用一个构造函数来创建另一个构造函数

15

假设你有以下两个构造函数:

- (id)initWithTitle:(NSString *)title;
- (id)initWithTitle:(NSString *)title page:(NSString *)page;

第二个构造函数与第一个没有区别,只是它设置了成员变量“page”。

既然基本上要做相同的事情,是否有办法从第二个构造函数中调用第一个构造函数以减少代码重复,或者您必须设置第三个方法来执行常见任务?

我正在讨论类似于这样的东西,尽管我怀疑这不会起作用:

- (id)initWithTitle:(NSString *)_title {
    if(self = [super init]) {
        self.title = _title;
    }

    return self;
}

- (id)initWithTitle:(NSString *)_title page:(NSString *)_page {
     if(self = [self initWithTitle:_title]) {
         self.page = _page;
     }

     return self;
}

2
@phunehehe有一个更好的解决方案,但你发布的内容确实可以工作。 - Dave DeLong
哦,我想现在想起来应该可以了。谢谢。 - synic
5
越早放弃C++术语,开始使用Objective-C术语,文档就会越快变得有意义。Objective-C没有构造函数或成员变量,而是有初始化方法和实例变量。 - bbum
2个回答

23

你说的有点奇怪,因为我在想着这个。

- (id)initWithTitle:(NSString *)_title {
    return [self initWithTitle:_title page:nil];
}

- (id)initWithTitle:(NSString *)_title page:(NSString *)_page {
    if(self = [super init]) {
        self.title = _title;
        self.page = _page;
    }
    return self;
}

它不起作用吗?


23

首先,你没有构造函数,你有两个初始化器:

- (id)initWithTitle:(NSString *)title;
- (id)initWithTitle:(NSString *)title page:(NSString *)page;

与大多数初始化器一样,目标是设置一些实例变量(而不是成员变量)。

第一步是确定您的指定初始化程序。在您的情况下,它可以是:

- (id)initWithTitle:(NSString *)title page:(NSString *)page;

这意味着- (id)initWithTitle:(NSString *)title;将会像其他人描述的那样实现:

- (id)initWithTitle:(NSString *)_title {
    return [self initWithTitle:_title page:nil];
}

然而,我建议避免这种模式,因为它会使得子类化比应该更容易出错。在子类化中,您必须始终覆盖指定的初始化程序或者实现调用指定初始化程序的新初始化程序。显然,您拥有的初始化程序越多,您可能会引入更多子类化错误。

此外,这个:

Foo *f = [[Foo alloc] initWithTitle: @"Foo!" page: nil];

比这个更清晰明了:

Foo *f = [[Foo alloc] initWithTitle: @"Foo!"];

第一个表明你已经专门考虑了 page 并且决定显式地将它设置为 nil 或者依赖于类 Foo 合理地设置页面。第二个没有这样的指示。

无论是子类化还是显式地指示意图,这些都是在 Cocoa 中找不到这种方便方法的主要原因(有一些,但大多数都相当古老——比实行这一政策更早)。


2
当你创建一个引入新的初始化程序的类别并且只想调用现有的初始化程序时,你无法避免这种模式。 - Καrτhικ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接