属性只是两个方法的集合:getter 和 setter。所以,当你写
@property (strong, nonatomic) NSString *name;
你真正想说的是
- (NSString *)name;
- (void)setName:(NSString *)name;
之后,每次编译器遇到obj.name 形式的表达式时,都会将其转换为[obj name]。每次看到obj.name = @"hello"; 之类的语句时,编译器都会将其转换为[obj setName:@"hello"]。
接下来您必须确保该属性的行为正常。你有很多选择:
- 手动编写 getter 和 setter,引用 iVar
- 合成 getter 和 setter
- 自动合成 getter 和 setter
- 编写自定义 getter 和 setter
- 使用
@dynamic 来避免编译时警告,因为您打算使用运行时魔法。 (真的,这不是您想要做的,因为您需要先了解基础知识。)
手动编写 getter 和 setter,引用 iVar
@interface MyClass : UIView {
NSString *_name;
}
@property (strong, nonatomic) NSString *name;
@end
在实现中
@implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
@end
合成getter和setter
最后一段基本相当于这个
@interface MyClass : UIView {
NSString *_name;
}
@property (strong, nonatomic) NSString *name;
@end
@implementation MyClass
@synthesize name = _name;
@end
自动合成 getter 和 setter
实际上,您只需使用“自动合成”即可。
@interface MyClass : UIView
@property (strong, nonatomic) NSString *name;
@end
@implementation MyClass
@end
这意味着,
- 如果你只是声明一个属性
- 不要打电话给
@synthesize或@dynamic
- 不要实现任何自定义 getter 和 setter
上面的代码将创建一个名为 _name 的 iVar 和一个 getter 和 setter,看起来与第一个示例中的完全一样。
这意味着前两个和这个部分是等价的,因为它们产生相同的代码。
编写自定义 getter 和 setter
这就是术语“动态属性”的真正含义。例如,您可能希望名称始终为大写。所以你可以写一个这样的属性。
@interface MyClass : UIView {
NSString *_name;
}
@property (copy, nonatomic) NSString *name;
@end
@implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name uppercaseString];
}
@end
(在上面的代码中,我将strong 更改为copy - 不用担心,这只是一个评论。这是一个真实的评论,因为uppercaseString 永远不会相同,它会始终是原件的副本。)
这可能是唯一真正有趣的案例!例如,这种属性是 UIKit 一直使用的,例如UILabel 的 text 属性就是这样的动态属性。它不仅设置了一些 iVar,而且还确保屏幕上的可见文本也发生变化。
@dynamic属性
他们真的很难做到正确,而且大多数时候他们不值得麻烦恕我直言。
注意:我简化了一些事情并省略了只有在使用 objc 运行时检查 API 时才能检测到的细节