为什么类别不能包含实例变量?

Rav*_*avi 18 objective-c objective-c-category ivar

我知道我们可以使用关联引用来调用类别中的类似于ivar的行为.但是,无法在类别中声明新的ivars背后的具体原因是什么?

是因为我们会入侵班级的私人空间吗?或者还有其他原因吗?如果是的话,我会很感激一个例子,它显示了在类别中声明ivars的能力,可以打破它所破坏的任何东西.

rma*_*ddy 25

将Objective-C的ivars想象成一个普通的旧C结构.实例化类的实例时,会创建一个足够大的内存块来保存该结构.

假设你有一个NSString.编译了许多现有代码以供使用NSString.很多代码都内置在库和框架中.已经编译的代码是在知道了iv的NSStringX字节并且在该内存中的某些给定偏移量的情况下创建的.

现在,在您自己的小项目中,您可以创建一个类别,NSString并希望添加一个ivar.理论上,项目中包含该类别头文件的任何代码都知道此"new" NSString(加上类别)的大小需要X + Y字节.这很像一个子类.这个新编译的代码可以正确处理额外的ivar.

但是所有预编译的代码,库和框架,都不了解额外的ivars.在NSString那里创建实例时,内存只有X字节,而不是X + Y字节.随着您的应用程序代码获取对较小内存块的引用并尝试访问类别ivar的字节,随之发生混乱.事情会好转.

对于一个普通的旧子类,事情是有效的,因为任何可以使用子类'ivars的代码都知道子类的ivars.但是对于类别,预先存在的代码不了解添加内容,也不会为它们正确创建空间.

我想我应该指出以上所有内容都是一个有根据的猜测.我完全错了.这似乎至少是合理的.:)

  • 顺便说一句,虽然上面的要点是真的(并且它*实际上是*),但是自ObjC2以来,关于间接分配的要点也是正确的.但它并没有真正帮助.类别在运行时附加,因此您必须有办法到达现有对象并修改其存储布局(直接或间接并不重要).这样的事情是可能的,但不是那种"我真的是一个在C之上的薄层,具有良好的运行时",这是ObjC的核心. (4认同)
  • 不允许类别添加存储是一个设计决策和实现细节.很早就决定,像限制点语法到强类型对象引用一样,不允许类别通过属性或其他方式添加存储是一个净积极因素. (2认同)