iOS底层学习-day-23
前言-OC-多线程篇
我是一名iOS开发者, iOS底层 菜鸟的进阶之路30天。
atomic
- 例子:
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
@property (nonatomic, assign) int age;
@property (atomic, copy) NSString *name;
@property (atomic, strong) NSMutableArray *data;//atomic 会加上加锁和解锁操作
@end
/*
nonatomic和atomic
atom:原子,不可再分割的单位
atomic:原子性
给属性加上atomic修饰,可以保证属性的setter和getter都是原子性操作,也就是保证setter和gette内部是线程同步的
// 加锁,原子属性就是把三行代码变成一句,变成一个整体,并不是说线程同步是安全的,只是说setter和getter内部是加锁安全的而已
int a = 10;
int b = 20;
int c = a + b;
// 解锁
*/
NSMutableArray *array = p.data;//p.data只有这个安全的
// 加锁
[array addObject:@"1"];
[array addObject:@"2"];
[array addObject:@"3"];
// 解锁
读写安全
-
思考如何实现以下场景
- 同一时间,只能有1个线程进行写的操作
- 同一时间,允许有多个线程进行读的操作
- 同一时间,不允许既有写的操作,又有读的操作
-
上面的场景就是典型的“多读单写”,经常用于文件等数据的读写操作,iOS中的实现方案有
- pthread_rwlock:读写锁
- dispatch_barrier_async:异步栅栏调用
-
pthread_rwlock - 读写锁
#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@property (assign, nonatomic) pthread_rwlock_t lock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化锁
pthread_rwlock_init(&_lock, NULL);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self read];
});
dispatch_async(queue, ^{
[self write];
});
}
}
- (void)read {
pthread_rwlock_rdlock(&_lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_lock);
}
- (void)write {
pthread_rwlock_wrlock(&_lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_lock);
}
- (void)dealloc {
pthread_rwlock_destroy(&_lock);
}
@end
- dispatch_barrier_async - 异步栅栏调用
- 这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的
- 如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果
//就是一定要自己创建DISPATCH_QUEUE_CONCURRENT,并发队列
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) dispatch_queue_t queue;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(self.queue, ^{
[self read];
});
dispatch_async(self.queue, ^{
[self read];
});
dispatch_async(self.queue, ^{
[self read];
});
dispatch_barrier_async(self.queue, ^{
[self write];
});
}
}
- (void)read {
sleep(1);
NSLog(@"read");
}
- (void)write {
sleep(1);
NSLog(@"write");
}
@end
NSProxy
- NSProxy 和NSObject同一级别,专门用来做消息转发的
- 例子1: timer的释放,是有问题的self->target->self所以会被强引用
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf timerTest];
}];
}
- (void)timerTest {
NSLog(@"%s", __func__);
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self.timer invalidate];
}
@end
- 例子2: - 例子1问题解决
- MJProxy.h
#import <Foundation/Foundation.h>
@interface MJProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
- MJProxy.m
#import "MJProxy.h"
@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
- 使用
#import "ViewController.h"
#import "MJProxy.h"
@interface ViewController ()
@property (strong, nonatomic) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[MJProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}
- (void)timerTest {
NSLog(@"%s", __func__);
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self.timer invalidate];
}
@end