属性访问

“对象”就是“基本构造单元”。开发者可以通过对象来存储并传递数据。

在对象之间传递数据并执行任务的过程就叫做“消息传递”

当程序裕兴起来以后,为其提供相关支持的代码叫做“Objective-C运行时环境”

它提供了一些使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑。

属性

property 是OC一项特性,用于封装对象中的数据。

尽量描述所有关于属性相关的问题

属性访问的点语法

属性由何而来

编译器自动合成

编译器生成getter setter 实例变量

@synthesize 指定实例变量名

@dynamic 告诉编译器不要自动创建实现属性的存取方法,不会报错,相信运行时一定能找到

1.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

1
2
3
4
5
6
7
8
9
10
11
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//与
@interface Person : NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end

编译识别一样,都能通过点语法访问属性,但是后者没有实现实例变量

读写权限readonly readwrite

默认是readwrite getter setter方法都会生成

readonly 只生成getter方法

原子性访问 atomic noatomic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}

// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;

// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();

// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}


static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}

id oldValue;
id *slot = (id*) ((char*)self + offset);

if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}

if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}

objc_release(oldValue);
}

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
bool mutableCopy = (shouldCopy == MUTABLE_COPY);
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}

void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, false, false);
}


void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, true, false);
}

void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}

可见编译器编译代码时,通过attribute识别在属性访问方法中插入对应方法

id *slot = (id*)((char*)self + offset)

slot 二级指针存储属性地址

分析atomic

set方法中

1
2
3
4
5
6
7
8
9
10
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}

如果是atomic 会在临界区加入自旋锁

oldValue 存储旧值指针

然后赋新值

get方法中

1
2
3
4
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();

那么,atomic能保证属性访问的线程安全吗

可以看到 在setter方法中,获取新值newValue时并未加锁,当多线程写的时候,并不能保证线程安全。

换句话说,它保证的是内存管理的安全。

内存管理语义
assign
通常针对“纯量类型” 的简单赋值操作
strong

此特质表明该属性定义了一种“拥有关系”,为这种属性设置新值时,设置方法会先保留新值,释放旧值,然后再将新值设置上去

weak
unsafe_unretained
copy

方法中的self msg_send 传进来的类

ARC