Ios 继承:限制而不是扩展?

Ios 继承:限制而不是扩展?,ios,objective-c,Ios,Objective C,假设您有一个UIView子类。您定义了一个init方法“myInitWithFrame:…等等:…”。您知道,您永远不会使用从UIView继承的init方法,并且您的自定义init方法会执行一些重要的自定义初始化,因此您希望强制客户机类永远不要使用继承的initWithFrame方法 是否可以隐藏从UIView继承的标准initWithFrame方法 否。您不能阻止子类的用户调用超类的方法。您可以重写它们并在内部抛出异常,但这只会产生一个损坏的子类 请记住,继承作为一个“is a”扩展工作,也就

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


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

否。您不能阻止子类的用户调用超类的方法。您可以重写它们并在内部抛出异常,但这只会产生一个损坏的子类

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


例如,UIKit不知道您的子类。因此,如果您想使UIView子类从NIB可用,则需要使用NIB加载系统将调用的初始化方法,即
initWithCoder:
。您只需在
initWithCoder:
中调用自己的初始化方法即可。但是,如果有任何附加参数要传递给init方法,则必须提供一种在初始化后配置这些参数的方法。

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

- (id) initWithFrame:(CGRect) frame __attribute__((unavailable("message")));
- (id) initWithFrame:(CGRect) frame
{
    return nil;     
}
这将使使用子类的任何人都无法使用
initWithFrame:
方法

要保持其他代码表单调用此方法,可以通过将其放入
.m
文件进一步限制

- (id) initWithFrame:(CGRect) frame __attribute__((unavailable("message")));
- (id) initWithFrame:(CGRect) frame
{
    return nil;     
}
实际上,您可以得到关于对子类调用方法的编译时警告。使用
\u属性((不推荐))
属性。如果希望人们使用
-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:
,如果它已经这样做了。但如果你能保证这不会发生,那你就没事了。

对。我确实传递了一些参数,这就是为什么我不能从标准方法中调用我的自定义方法。嗯,这真是一个两难的选择。下面是一个大型开源项目中关于这个主题的讨论——AFNetworking最近决定在
init
中抛出一个异常:谢谢!特别是在我已经接受了另一个答案之后发布。这太棒了!如果我尝试将这两个内容放入视图的头文件中,它将无法编译。它声称该属性具有错误数量的参数。我可以通过使用
-(id)initWithFrame:(CGRect)frame uuu属性_uu((不推荐))来“修复”它并使其编译取而代之。然后它进行编译,但没有任何警告,即使我在其他地方调用此方法以引发compiler warning.Hm。您使用的是最新版本的Xcode吗?我使用的是Xcode 4.6.2,我提供的代码会在调用时编译并提供警告。对不起,不,我没有。:)这似乎无法编译。但是,如果我去掉这个论点,它会。将第二个建议添加到类中会产生一个编译器警告“只能在方法声明中指定方法属性”。但即便如此:我发现你的答案非常有用,投票给你也没什么错!也许您可以编辑您的答案并修改第一段代码以便编译?不要在实现上添加属性或完全忽略实现。我将此答案复制并粘贴到Xcode中,它在我的机器上编译。也许你可以告诉我你看到的错误?哦,对不起,我的第二个评论应该是“…以便编译时没有错误”。对不起,怎么是复制品?