在Objective-C中,为什么类继续可以添加实例变量但类类不能?

时间:2014-04-09 09:04:51

标签: objective-c

我知道我们不能在类类别中添加实例变量,但我们可以添加类继续,可以告诉我为什么或者给我一些关于它的细节。 我知道我们可以在类别中使用关联,我想知道有关实现的详细信息。 非常感谢。

2 个答案:

答案 0 :(得分:6)

TL;博士

类扩展仅修改您拥有的类,而类别可以修改任何现有类。

将ivars添加到现有类可能会破坏旧运行时(iOS或OSX 64位之前)的二进制兼容性,这就是禁止的原因。

添加方法不会遇到此问题,因为方法解析始终是动态的。


讨论

因为类扩展(clang调用类continuation )不是类别,尽管它们有共同之处。

来自Apple文档

  

类扩展与类别有一些相似之处,但是它只能添加到您在编译时拥有源代码的类(该类与编译时同时编译类扩展)。类扩展声明的方法在原始类的<{1}}块中实现,因此您不能在框架类上声明类扩展,例如Cocoa或者像NSString一样的Cocoa Touch类。

类扩展在编译时扩展了类的接口:这是代码组织和可见性的简单问题(例如,声明私有属性很有用)。

您只是将@implementation声明分成多个部分,但是您无法向现有的类添加任何内容。

由于这个原因,自然支持添加ivar。大概你可以这样做:

@interface

@interface MyClass : NSObject {
    NSInteger a;
    NSInteger b;
}
@end

并且几乎等效(如果您将类扩展名放在私有的.m文件中,那么@interface MyClass : NSObject { NSInteger a; } @end @interface MyClass() { NSInteger b; } @end 将是私有的。)

另一方面,对于班级类别,您可以修改任何类。

这是至关重要的,因为在设计类别时,Objective-C具有脆弱的基础ivars

这是什么意思?这意味着一旦编译了一个类,ivars布局就永远固定在二进制文件中,你不能修改它而不破坏与类的任何子类的二进制兼容性。

因此,在b中添加一个ivar会破坏(几乎)每个编译的框架中的每个类

相反,方法是动态解析的,因此只要您没有名称冲突,就可以安全地将方法添加到现有类中。

自从第一个iOS(当时的iPhone OS)和使用动态ivars的64位OSX以来,脆弱的ivar问题得到了解决,但Objective-C无法在不破坏与32-的兼容性的情况下利用此功能咬麦克风。


参考

http://www.sealiesoftware.com/blog/archive/2009/01/27/objc_explain_Non-fragile_ivars.html http://www.cocoawithlove.com/2010/03/dynamic-ivars-solving-fragile-base.html

答案 1 :(得分:-1)

仅仅因为class extension可以完成这项工作。

@interface SimpleClass : NSObject
@property int someProperty;
@end

@interface Foo()
@property float aNewProperty; // added through class extension 
@end
PS:不要在Objective-C中继续提出这样的问题。因为Objective-C不同,这里的不同意味着真正不同。您是否曾在Objective-C中看到过AbstractProtected个关键字?没有为什么? Objective-C不同。