继承:限制而不是扩展?

时间:2013-05-31 16:15:10

标签: ios objective-c

假设您有一个UIView子类。您定义了一个init方法“myInitWithFrame:... andWhatNot:...”。您知道您将不会使用从UIView ever 继承的init方法,并且您的自定义init方法会执行一些重要的自定义初始化,因此您希望强制客户端类永远不要使用继承的initWithFrame方法。

是否可以隐藏从UIView继承的标准initWithFrame方法?

3 个答案:

答案 0 :(得分:20)

实际上,可以获取有关在子类上调用方法的编译时警告。使用__attribute((deprecated))属性。如果您希望人们使用-initWithPizza:代替-initWithFrame:,请执行以下操作:

@interface MyView : UIView
- (id)initWithPizza:(MyPizza *)pizza;
@end

@interface MyView (Deprecations)
- (id)initWithFrame:(CGRect)frame __attribute((deprecated("Use initWithPizza: instead")));
@end

-initWithFrame:声明放在一个单独的类别中是必要的,以避免Xcode抱怨您在标头中声明了方法但没有实现它。既然你只是从超类继承它,那很好;你根本没有 来实现它。但是如果你想实现它来抛出异常,或者使用默认参数调用-initWithPizza:,那很好。

当然,这不会阻止UIKit调用-initWithFrame:,如果它已经这样做的话。但如果你能保证不会发生,那你就没事了。

答案 1 :(得分:7)

实际上,您可以使用子类进行限制。您可以覆盖要在子类的.h文件中阻止的任何方法。您可以将以下内容放入initWithFrame文件中,以使.h无法使用。

- (id) initWithFrame:(CGRect) frame __attribute__((unavailable("message")));

这将使initWithFrame:方法对使用您的子类的任何人都不可用。

要保留调用此方法的其他代码形式,您可以将其放在.m文件中进一步限制。

- (id) initWithFrame:(CGRect) frame
{
    return nil;     
}

答案 2 :(得分:3)

没有。您无法阻止子类的用户调用超类的方法。你可以覆盖它们并在里面抛出一个异常,但这只会产生一个破坏的子类。

请记住,继承作为“是扩展名工作,也就是说,子类的实例应该在任何不了解此特定子类但知道其超类的上下文中正常运行。只有在您明确了解子类的地方才能从添加额外的初始化和其他方法中受益。

例如,UIKit不了解您的子类。因此,如果要从NIB提供UIView子类,则需要使用NIB加载系统调用的初始化方法,即initWithCoder:。您只需在initWithCoder:内调用自己的初始化方法即可。但是,如果您希望将任何其他参数传递给init方法,则必须提供一种在初始化后配置它们的方法。