Objective-C中的inheritance和类别有什么区别?

有人可以向我解释目标C中类别和inheritance之间的区别吗? 我已阅读维基百科的条目,关于类别的讨论与inheritance没有任何区别。 我也在“开放iPhone开发”一书中讨论了这个话题的讨论,但我仍然不明白。

有时候,inheritance似乎比它更值钱。 当你想添加一些东西到一个已经存在的类中时,它就被正确地使用了。

有了类别,你只需要现有的对象做更多一点。 正如已经指出的那样,如果你只是想要一个处理压缩的string类,你不需要子类化string类,你只需创build一个类来处理压缩。 这样,你不需要改变你已经使用的string类的types。

线索的限制是类只添加方法,不能使用类添加variables到类中。 如果这个类需要更多的属性,那么它就必须被子类化(编辑:你可以使用联想存储,我相信)。

类别是添加function的好方法,同时符合面向对象的原则,使得组合优于inheritance。

编辑2012年1月

事情现在已经改变了。 使用当前的LLVM编译器和现代的64位运行时,可以将IVARS和属性添加到类扩展 (而不是类别)。 这使您可以将私人iVar保留在公共界面之外。 但是,如果你声明了iVars的属性,那么仍然可以通过KVC访问/更改它们,因为Objective-C中仍然没有私有方法。

类别允许您将方法添加到现有的类。 因此,而不是子类NSData来添加你时髦的新encryption方法,你可以直接添加到NSData类。 您的应用程序中的每个NSData对象现在都可以访问这些方法。

看看这可以是多么有用,看看: CocoaDev

Objective-c类别最受欢迎的插图之一是NSString。 NSString是在Foundation框架中定义的,它没有视图或窗口的概念。 但是,如果您在Cocoa应用程序中使用NSString,则会注意到它会响应类似于– drawInRect:withAttributes:消息。

AppKit为NSString定义了一个提供额外绘图方法的类别。 该类允许将新的方法添加到现有的类,所以我们仍然只是处理NSString。 如果AppKit改为通过inheritance来实现绘图,那么我们必须处理'AppKitStrings'或'NSSDrawableStrings'或类似的东西。

类别允许您将应用程序或特定于域的方法添加到现有类中。 它可以相当强大和方便。

如果你作为一个程序员给了一个完整的代码库或应用程序的源代码,你可以坚持不懈地改变任何你需要的代码来实现你的编程目标。

不幸的是,情况并非总是如此,甚至是不可取的。 很多时候,您会得到一个二进制库/对象工具包和一组头文件。

然后,一个新的function需要一个类,所以你可以做几件事情:

  1. 创build一个新的类而不是一个股票类 – 复制所有的function和成员,然后重写所有的代码来使用新的类。

  2. 创build一个包含作为成员的股票类(合成)的新包装类,并重写代码库以使用新类。

  3. 库的二进制补丁来改变代码(祝你好运)

  4. 强制编译器将旧类视为新类,并希望它不依赖于内存和特定入口点的特定大小或位置。

  5. 子类专门化 – 创build子类来添加function和修改驱动程序代码来使用子类 – 理论上应该有一些问题,如果你需要添加数据成员是必要的,但内存占用将是不同的。 您可以在子类中使用新代码和旧代码,并select要使用的代码,基类方法或重写的方法。

  6. 使用包含方法的类别定义修改必要的objc类,以便执行所需的操作和/或覆盖库存类中的旧方法。

    这也可以修复库中的错误或自定义新硬件设备的方法等等。 这不是万能的,但是它允许添加类方法,而不用重新编译没有改变的类/库。 原始类在代码,内存大小和入口点是相同的,所以传统应用程序不会中断。 编译器只是简单地把新的方法放入运行时,作为属于那个类,并覆盖与原始代码相同的签名方法。

    一个例子:

    你有一个Bing输出到terminal,但不是串口,现在这就是你所需要的。 (因为某些原因)。 你的工具包中有Bing.h和libBing.so,但不是Bing.m。

    Bing类在内部做各种各样的东西,你甚至不知道什么,你只是在头上的公共api。

    你很聪明,所以你为Bing类创build一个(SerialOutput)类别。

     [Bing_SerialOutput.m] @interface Bing (SerialOutput) // a category - (void)ToSerial: (SerialPort*) port ; @end @implementation Bing (SerialOutput) - (void)ToSerial: (SerialPort*) port { ... /// serial output code /// } @end 

    编译器有义务创build一个可以与应用程序链接的对象,运行时现在知道Bing响应@selector(ToSerial :),并且可以像使用该方法构buildBing类一样使用它。 你不能只添加数据成员的方法,这不是为了创build巨大的代码附加到基类的肿瘤,但它确实有优于严格types的语言的优势。

Category是Objective-C语言的一个特性,它使您能够将方法(接口和实现)添加到类中,而无需创build子类。 在程序范围内,类的原始方法和类别添加的方法之间没有运行时差异。 类别中的方法成为类types的一部分,并由所有类的子类inheritance。

和代表团一样,类别并不是对装饰者模式的严格适应,实现了意图,而是采取了不同的途径来实现这个意图。 按类别添加的行为是编译时工件,并不是dynamic获取的。 而且,类别不会封装正在扩展的类的一个实例。

Cocoa框架定义了许多类别,其中大多数是非正式协议。 他们经常使用类别来分组相关的方法。 您可以在您的代码中实现类别来扩展不带子类的类或将相关方法分组。 但是,你应该知道这些警告:

– >你不能将实例variables添加到类中。
– >如果您覆盖了该类的现有方法,那么您的应用程序可能会performance出不可预测性。

我认为其中的一些答案至less指出inheritance是向现有类添加function的更重要的方式,而类更加轻量化。

当你创build一个新的类层次结构(所有的花里胡哨的)时,inheritance被使用,并且当被select作为向现有类中添加function的方法时,可以说是带来了很多工作。

正如其他人在这里所说的…如果你正在使用inheritance来添加一个新的方法,例如NSString,你必须去改变你在其他代码中使用这个新方法的types。 但是,如果您使用类别,则只需在现有的NSStringtypes上调用该方法,而无需进行子类化。

同样的目标也可以实现,但类别似乎给了我们一个更简单的select,需要更less的维护(可能)。

任何人都知道是否有类别绝对必要的情况?

一个类就像一个mixin:一个Ruby中的模块,或者有点像Java中的一个接口。 你可以把它想成“裸体方法”。 当你添加一个类别时,你正在为这个类添加方法。 维基百科的文章有很好的东西 。

研究这种差异的最好方法是:1.inheritance:当想要完全按照自己的方式完成时。 例如:AsyncImageView实现延迟加载。 这是通过inheritanceUIView完成的。 2.类别:只是想添加一个额外的味道。 例如:我们想要replace文本字段文本中的所有空格

  @interface UITextField(setText) - (NSString *)replaceEscape; @end @implementation UITextField(setText) - (NSString *)replaceEscape { self.text=[self.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return self.text; } @end 

—它将添加一个新的属性到文本字段为您逃脱所有的空格。 就像添加一个新的维度,而不是完全改变它的方式。

Interesting Posts