一、属性关键字
1 @property、@synthesize 和 @dynamic
@interface TestA : NSObject
@property() NSString *name;
@property() NSString *synthesizeName;
@property() NSString *dynamicName;
@end
@implementation TestA
@synthesize synthesizeName = customName;
@dynamic dynamicName;
@end
用clang -rewrite-objc main.m转为c++
struct TestA_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *customName;
NSString *_name;
};
// @property() NSString *name;
// @property() NSString *synthesizeName;
// @property() NSString *dynamicName;
/* @end */
// @implementation TestA
// @synthesize synthesizeName = customName;
static NSString * _I_TestA_synthesizeName(TestA * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$customName)); }
static void _I_TestA_setSynthesizeName_(TestA * self, SEL _cmd, NSString *synthesizeName) {
(*(NSString **)((char *)self + OBJC_IVAR_$_TestA$customName)) = synthesizeName; }
// @dynamic dynamicName;
static NSString * _I_TestA_name(TestA * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)); }
static void _I_TestA_setName_(TestA * self, SEL _cmd, NSString *name) {
(*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)) = name; }
// @end
- @property会变为getter、setter方法的声明,与之对应的一个是@synthesize,一个是@dynamic;
- @synthesize由编译器合成getter、setter方法的实现,也会合成带下划线的成员变量;
不自动合成的情况:- 同时重写了 setter 和 getter 时
- 重写了只读属性的 getter 时
- 使用了 @dynamic 时
- 在 @protocol 中定义的所有属性
- 在 category 中定义的所有属性
- 重载的属性
- @dynamic由用户自己去实现getter、setter方法和需要的成员变量。
具体请参考官方文档: Encapsulating Data
2 nonatomic、atomic
- atomic是表示属性原子性,范围仅限于setter方法内,属性原子性不是对象线程安全的同义词。默认为atomic。
- nonatomic就是非原子性。
3 readwrite、readonly
- readwrite就是要生成或自己实现get和set方法, 默认是readwrite。
- readonly只要求生成或自己实现get方法。
4 strong、retain、weak、assign、copy、unsafe_unretained
- strong ARC下默认,引用计数+1
- retain ARC下一般用strong,引用计数+1
- weak 一般用于避开循环引用,对象释放会自动置为nil,引用计数不变
- assign 基本类型的默认修饰符,也可以用于对象,引用计数不变,不会置nil
- copy 不可变对象是浅拷贝, 可变对象是深拷贝,返回的都为不可变对象
- unsafe_unretained 只能用于对象,引用计数不变,不会置nil,会变为野指针
5 nullable、nonnull
- nullable就是指针可为nil
- nonnull就是指针不可为nil。这两个都不是默认的,需要显式指出。
6 属性修饰符分析
6.1 objc_getProperty与objc_setProperty
@interface TestA : NSObject
@property(nonatomic) NSString *name;
@property(atomic) NSString *name1;
@property(copy) NSString *name2;
@property(nonatomic, copy) NSString *name3;
@end
@implementation TestA
@end
转为c++
static NSString * _I_TestA_name(TestA * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)); }
static void _I_TestA_setName_(TestA * self, SEL _cmd, NSString *name) {
(*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)) = name; }
static NSString * _I_TestA_name1(TestA * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name1)); }
static void _I_TestA_setName1_(TestA * self, SEL _cmd, NSString *name1) {
(*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name1)) = name1; }
extern "C" __declspec(dllimport) id objc_getProperty(id, SEL, long, bool);
static NSString * _I_TestA_name2(TestA * self, SEL _cmd) {
typedef NSString * _TYPE;
return (_TYPE)objc_getProperty(self, _cmd, __OFFSETOFIVAR__(struct TestA, _name2), 1); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_TestA_setName2_(TestA * self, SEL _cmd, NSString *name2) {
objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestA, _name2), (id)name2, 1, 1); }
static NSString * _I_TestA_name3(TestA * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name3)); }
static void _I_TestA_setName3_(TestA * self, SEL _cmd, NSString *name3) {
objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestA