属性的存储
- 关联对象(Associated Objects):
- 在Objective - C运行时,属性可以通过关联对象机制来存储值。这种方式允许为对象动态添加属性,即使类在编译时没有定义这些属性。
- 运行时使用
objc_setAssociatedObject
函数来设置关联对象,objc_getAssociatedObject
函数来获取关联对象。例如:
#import <objc/runtime.h>
@interface MyClass : NSObject
@end
@implementation MyClass
static char myPropertyKey;
- (void)setMyProperty:(id)value {
objc_setAssociatedObject(self, &myPropertyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)myProperty {
return objc_getAssociatedObject(self, &myPropertyKey);
}
@end
- 实例变量(Ivar):
- 类定义中的属性通常会对应一个实例变量(Ivar),它是对象在内存中的一部分。编译器会自动为属性生成对应的实例变量,其命名规则通常是以
_
开头加上属性名。例如,对于属性name
,会生成实例变量_name
。
- 实例变量存储在对象的内存结构中,其内存布局由运行时根据类的定义确定。对象在创建时,会为实例变量分配内存空间。
访问方法的生成
- 自动合成(Auto - Synthesis):
- 从Xcode 4.4开始,编译器默认会自动为属性合成访问方法(getter和setter)。当在类中声明一个属性,如
@property (nonatomic, strong) NSString *name;
,编译器会在后台自动生成name
的getter方法- (NSString *)name
和setter方法- (void)setName:(NSString *)name
。
- 对于只读属性(
@property (readonly)
),只会生成getter方法。
- 自定义访问方法:
- 如果开发者手动实现了访问方法,编译器就不会自动合成。例如,如果手动实现了
- (NSString *)name
和- (void)setName:(NSString *)name
方法,那么运行时会使用开发者定义的这些方法来访问属性。
- 在自定义访问方法中,可以实现更复杂的逻辑,比如在setter方法中进行数据验证,在getter方法中进行数据的延迟加载等。例如:
- (void)setName:(NSString *)name {
if (name.length > 0) {
_name = name;
}
}
- (NSString *)name {
if (!_name) {
_name = @"Default Name";
}
return _name;
}
- 方法查找与消息转发:
- 当通过点语法或消息发送方式访问属性(如
object.name
或[object name]
)时,运行时首先会在类的方法列表中查找对应的访问方法。
- 如果没有找到,会进行动态方法解析,尝试动态添加方法。若动态方法解析失败,会进入备用接收者阶段,看是否有其他对象可以处理该消息。若仍失败,最终会进行完整的消息转发流程,包括
forwardInvocation:
和methodSignatureForSelector:
等方法的调用,以处理未识别的方法调用。