在 Objective-C 中,实例变量(ivars)的偏移值确实是在编译时确定的,而方法(使用 `category` 或 `class_addMethod`)可以在运行时动态添加。这种设计差异基于以下几个原因:
1. 内存布局的稳定性:
对象的内存布局在编译时确定是为了保证对象的大小和实例变量的位置在对象的生命周期中是固定的。如果允许在运行时动态添加实例变量,那么可能需要重新分配对象的内存,这会引入大量的复杂性,并可能导致指向旧对象的指针失效。
2. 性能:
直接使用固定的偏移量来访问实例变量是非常快速的,因为这只涉及简单的地址计算。如果实例变量可以在运行时动态添加,那么访问它们可能需要更复杂、更慢的查找机制。
3. 简化模型:
限制实例变量的添加简化了 Objective-C 的对象模型。允许在运行时动态添加实例变量会引入许多复杂的问题,例如:如何处理已存在的对象实例?新添加的实例变量的默认值是什么?如何处理对象的归档和解档?
4. 方法与实例变量的不同:
方法只是函数指针,并存储在类的方法列表中,而不是在每个对象实例中。添加新方法不会影响已存在的对象的大小或内存布局。而实例变量是对象状态的一部分,存储在每个对象实例中,所以其内存布局的考虑因素与方法不同。
尽管如此,Objective-C 运行时确实提供了一些高级功能,如关联对象(Associated Objects),它允许你在运行时动态地将值与特定的对象实例关联。这可以用作在运行时为对象添加“实例变量”的代替方法,但其性能和直接访问实例变量的性能相比可能会较低。