使用分类覆写Objective-C中的方法

90

我可以使用一个类别(category)来覆盖已经使用另一个类别实现的方法吗?就像这样:

1)原始方法

-(BOOL) method {
  return true;
}

2) 重写方法

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

这个行得通吗,还是说会有违法的问题?

4个回答

152

根据 Apple 文档:

虽然 Objective-C 语言目前允许使用分类来重写类继承的方法,甚至是类接口中声明的方法,但强烈不建议这样做。分类不能替代子类。使用分类重写方法有几个明显的缺点:

  • 当一个分类重写一个继承的方法时,分类中的方法可以像往常一样通过消息发送到 super 来调用继承的实现。然而,如果一个分类重写了存在于该分类所属类中的方法,则没有办法调用原始实现

  • 一个分类无法可靠地重写同一类的另一个分类中声明的方法。

    这个问题尤其重要,因为许多 Cocoa 类都是使用分类实现的。你试图重写的一个框架定义的方法可能已经在一个分类中实现,因此哪个实现会优先使用是未定义的。

  • 某些分类方法的存在可能会导致所有框架的行为发生变化。例如,如果你在 NSObject 上的一个分类中重写 windowWillClose: 委托方法,那么程序中所有窗口委托都将使用该分类方法进行响应;所有 NSWindow 实例的行为可能会发生变化。在框架类上添加的分类可能会导致行为发生神秘的变化,并导致崩溃。


1
谢谢您的建议。我在这门语言方面很差。我从您那里得到了新的信息。 - retix
1
在父类的类别中声明和实现的类别方法中覆盖,这样做是否正确? - BergP
我认为是的!你的子类将会覆盖父类。 - Benoît
我已经做过这个操作多次,没有遇到任何问题。我必须这样做才能定制一个应用程序的某些方面,该应用程序是从另一个应用程序继承而来的(一种新的应用程序目标,但不完全相同,也不容易通过新的目标解决):使用类别,我可以通过导入mainclass.h保留相同的代码,而通过导入mainclass+category.h使用新的方法。 - Fabio Napodano
2
链接已经失效了,这是新版本的链接吗?https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html - RndmTsk
显示剩余6条评论

18

9

旧的文件链接已经失效,我所能找到的最佳替代品是这里:Apple Docs

避免类别方法名称冲突

由于在类别中声明的方法添加到现有类中,因此您需要非常小心地处理方法名称。

如果在类别中声明的方法名称与原始类中的方法名称相同,或与同一类别中(甚至是超类)的另一个方法名称相同,则行为未定义,无法确定在运行时使用哪个方法实现。如果您正在使用类别与自己的类一起使用,则可能不太可能出现此问题,但是在使用类别将方法添加到标准Cocoa或Cocoa Touch类中时可能会导致问题。

这是苹果使用了更轻柔的方式,但主要观点是相同的:您会引发灾难,因为不可预测的行为是沉默的。


2
重要的是要注意,类别还可以用于覆盖基类中的现有方法(例如Car类的drive方法),但是您永远不应该这样做。问题在于,类别是一种扁平的组织结构。如果您在Car+Maintenance.m中覆盖了现有方法,然后又决定使用另一个类别再次更改其行为,那么Objective-C无法知道要使用哪个实现。在这种情况下,子类化几乎总是更好的选择。
来自本教程,http://rypress.com/tutorials/objective-c/categories

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