学习MJ的视频课程,整理总结知识点–atomic、读写安全、定时器

atomic

atomic:原子,不可再分割的单位
保证setter和getter内部实现是线程同步的
但是不能保证同时setter、getter时线程同步,要想实现setter、getter的安全,这两个函数内部要重写并自己加锁,或者在调用这两个函数的地方加锁。

iPhone不适用:调用频率高,都加锁解锁耗性能

1、atomic不能保证安全(同步锁),为何;如何保证
Atomic使用的是自旋锁,在setter和getter加锁spinlock_t,不能保证真正的线程安全,如果多个线程同时读写这个值,某个线程就会获取到错误的值

读写安全

多读单写:读时可并发读、写仍然是单线程;读写之间也是互斥

1
2
pthread_rwlock:读写锁
dispatch_barrier_async:异步栅栏调用

pthread_rwlock

等待锁的线程会进入休眠
pthread_rwlock

runtime源码中有不少地方用到pthread_rwlock

dispatch_barrier_async

这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的
如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果
d499f7b8-03a7-439d-a0ec-77596c798610

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
- (void)viewDidLoad {
[super viewDidLoad];

self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);

for (int i = 0; i < 10; i++) {
[self read];
[self read];
[self read];
[self write];
}
}

- (void)read {
dispatch_async(self.queue, ^{
sleep(1);
NSLog(@"read");
});
}

- (void)write {
dispatch_barrier_async(self.queue, ^{
sleep(1);
NSLog(@"write");
});
}

dispatch_barrier_async

定时器

CADisplayLink、NSTimer使用注意

NSTimer

解决循环引用
1、timer的block初始化方式
2、自定义target,通过消息转发给原target

NSProxy

特殊的类
存在的意义:解决代理转发行为
做消息转发的话相比NSObject效率更高,少了去父类搜索的流程和动态方法解析的阶段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@implementation MJProxy
+ (instancetype)proxyWithTarget:(id)target {
// NSProxy对象不需要调用init,因为它本来就没有init方法
MJProxy *proxy = [MJProxy alloc];
proxy.target = target;
return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end

NSProxy大部分方法底层都没有实现,调用时很容易就消息转发了,会调用Target的方法

总结

参考和源码

源码:

评论