Objective-C是否像Ruby一样支持Mixin?

在Ruby中,有模块,您可以通过“混入”模块来扩展类。

module MyModule def printone print "one" end end class MyClass include MyModule end theOne = MyClass.new theOne.printone >> one 

在Objective-C中,我发现我有一组常用的方法,我想要一些Class来“inheritance”。 如果不创建一个公共类并从该公共类派生所有其他方法,我可以通过什么方式实现这一目标?

编辑 :添加了更改,因为有些人认为我负责Objective-C的限制。

简答 :你不能。 Objective-C没有Ruby mixins的等价物。

稍微简短的回答 :Objective-C确实有一些可以说是相同的味道:协议。 协议(一些其他语言中的接口)是一种定义一组方法的方法,该类采用该协议承诺实现。 但协议不提供实现。 这种限制阻止使用协议作为Ruby mixins的精确等价物。

更简短的回答:但是,Objective-C运行时有一个公开的API,可以让您使用该语言的动态function。 然后你走出语言,但你可以拥有默认实现的协议(也称为具体协议)。 弗拉基米尔的答案显示了一种方法。 在这一点上,在我看来你得到Ruby mixins没问题。

但是,我不确定我会建议那样做。 在大多数情况下,其他模式符合条件,而无需使用运行时游戏。 例如,您可以拥有一个实现混合方法的子对象( has-a而不是is-a )。 使用运行时是可以的,但有两个缺点:

  • 您使代码的可读性降低,因为它要求读者知道的语言远远多于语言。 当然你可以(并且应该)对它进行评论,但请记住,任何必要的评论都可以被视为实施缺陷。

  • 您依赖于该语言的实现。 当然,Apple平台是迄今为止最常见的Objective-C平台,但不要忘记Cocotron或GnuStep(或Etoilé)具有不同的运行时间,在这方面可能与Apple兼容,也可能不兼容。

作为旁注,我在下面说明类别不能将状态(实例变量)添加到类中。 通过使用运行时API,您也可以解除该限制。 然而,这超出了这个答案的范围。

答案很长:

两个Objective-Cfunction看起来像是可能的候选者:类别和协议。 如果我理解这个问题,那么类别在这里并不是正确的选择。 正确的function是协议。

让我举个例子。 假设您希望一堆类具有称为“sing”的特定function。 然后定义一个协议:

 @protocol Singer - (void) sing; @end 

现在,您可以通过以下方式声明您自己的任何类都采用该协议:

 @interface Rectangle : Shape  {  @end @interface Car : Vehicle  {  @end 

通过声明他们采用协议,他们承诺实现sing方法。 例如:

 @implementation Rectangle - (void) sing { [self flashInBrightColors]; } @end @implementation Car - (void) sing { [self honk]; } @end 

然后你使用这些类,例如:

 void choral(NSArray *choir) // the choir holds any kind of singer { id aSinger; for (aSinger in choir) { [aSinger sing]; } } 

请注意,数组中的歌手不需要具有共同的超类。 另请注意,一个类只能有一个超类,但许多采用的协议。 最后注意,类型检查由编译器完成。

实际上,协议机制是用于mixin模式的多重inheritance。 由于协议无法向类中添加新的实例变量,因此多重inheritance受到严重限制。 协议仅描述了采用者必须实现的公共接口。 与Ruby模块不同,它不包含实现。

这是最重要的。 但是,让我们提一下类别。

声明的类别不在尖括号中,而是在括号之间声明。 不同之处在于可以为现有类定义类别以扩展它,而无需对其进行子类化。 您甚至可以为系统类执行此操作。 可以想象,可以使用类别来实现类似于mixin的东西。 并且它们通常以这种方式使用,通常作为NSObject (inheritance层次结构的典型根)的类别,在某种程度上它们被称为“非正式”协议。

它是非正式的,因为1-编译器没有进行类型检查,并且实现协议方法是可选的。

今天不需要使用类别作为协议,特别是因为正式协议现在可以声明它们的一些方法对于关键字@optional是可选的,或者是@optional必需(默认)。

类别对于向现有类添加某些特定于域的行为仍然很有用。 NSString是一个常见的目标。

有趣的是,指出大多数(如果不是全部) NSObject工具实际上是在NSObject协议中声明的。 这意味着使用NSObject作为所有类的公共超类并不是真的很有吸引力,尽管这仍然是出于历史原因通常做的,而且……因为这样做没有任何缺点。 但是一些系统类,如NSProxy不是 NSObject

无耻插头: ObjectiveMixin

它利用了Objective-C运行时在运行时向类添加方法的能力(与类别相反,只是编译时)。 看看它,它的工作非常好,并且与Ruby的mixins类似。

您可以使用#include从字面上混合代码。 这是不可取的,并且反对目标c中的所有宗教,但是效果很好。

请不要在生产代码中执行此操作。

例如在文件中:

MixinModule.header (不应编译或复制到目标)

 -(void)hello; 

MixinModule.body (不应编译或复制到目标)

 -(void)hello{ NSLog(@"Hello"); } 

在mixin类中:

 @interface MixinTest : NSObject #include "MixinModule.header" @end @implementation MixinTest #include "MixinModule.body" @end 

使用案例:

 #import  int main(int argc, const char * argv[]){ @autoreleasepool { [[[MixinTest new] autorelease] hello]; } return 0; } 

请不要在生产代码中执行此操作。

这是我在Objective-C中实现Mixins的看法,而不直接使用Objective-C运行时。 也许这对某人有帮助: https : //stackoverflow.com/a/19661059/171933