iOS 多线程的四种技术方案
image
pthread 实现多线程操作 代码实现: void * run(void *param) { for (NSInteger i = 0; i < 1000; i++) { NSLog(@"---buttonclick---%zd---%@", i, [NSThread currentThread]); } return NULL; } @implementation ViewController - (IBAction)clickButton:(id)sender { // 定义一个线程 pthread_t thread; // 创建一个线程 (参1)pthread_t *restrict:创建线程的指针,(参2)const pthread_attr_t *restrict:线程属性 (参3)void *(*)(void *):线程执行的函数的指针,(参4)void *restrict:null pthread_create(&thread, NULL, run, NULL); // 何时回收线程不需要你考虑 pthread_t thread2; pthread_create(&thread2, NULL, run, NULL); } NSThread实现多线程一个 NSThread 对象就代表一条线程 创建线程的多种方式
#pragma mark - 执行run方法 - (void)run:(NSString *)param { // 当前线程是否是主线程 for (NSInteger i = 0; i < 100; i++) { NSLog(@"---%@---%zd---%d", [NSThread currentThread], i, [NSThread isMainThread]); } }
方法2和方法3的优点:快捷 -(UIImageView *)imageView { if (!_imageView) { _imageView = [UIImageView new]; _imageView.frame = CGRectMake(0, 0, 300, 300); _imageView.center = self.view.center; [self.view addSubview:_imageView]; } return _imageView; } - (void)viewDidLoad { [super viewDidLoad]; //监听线程结束的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_threadexit:) name:NSThreadWillExitNotification object:nil]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //第一种方式:先创建再启动线程 // 创建线程 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"booob"]; // 线程启动了,事情做完了才会死, 一个NSThread对象就代表一条线程 [thread start]; //第二种:直接创建并启动线程 // 直接创建并启动线程 [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"wang"]; //第三种: // 直接创建并启动线程 [self performSelectorInBackground:@selector(run:) withObject:@"wang000"]; // 使线程进入阻塞状态 [NSThread sleepForTimeInterval:2.0]; //例子 // 获取图片的url NSURL *url = [NSURL URLWithString:@"https://pages.github.com/images/slideshow/yeoman.png"]; // 另开1条线程 object用于数据的传递 NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(downLoadWithURL:) object:url]; thread3.name = @"downloadimage..."; // 由于下面下载图片的耗时太长,应开启线程来完成 [thread3 start]; } #pragma mark - 执行run方法 - (void)run:(NSString *)param { // 当前线程是否是主线程 for (NSInteger i = 0; i < 10; i++) { NSLog(@"---%@---%zd---%d", [NSThread currentThread], i, [NSThread isMainThread]); } } //线程直接的交互 // 下载图片 - (void)downLoadWithURL:(NSURL *)url { NSLog(@"%s ,%s %@",__FILE__,__FUNCTION__, [NSThread currentThread]); // 下载图片 NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片 UIImage *image = [UIImage imageWithData:data]; // 返回主线程显示图片 [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; } //处理线程结束事件 -(void)handle_threadexit:(NSNotification *)notify { NSThread * thread = (NSThread *)notify.object; NSLog(@"+++++++++++++++ 线程 %@ 结束 ++++++++++++",thread.name); }
TIPS: 拓展,线程结束的通知 —————————————————————————————————————————— GCD 是如何实现多线程的
images
GCD会自动将队列中的任务取出,放到对应的线程,任务的取出遵循FIFO,即先入先出队列,First Input First Output 的缩写。
创建并发/串行队列代码: - (void)viewDidLoad { [super viewDidLoad]; dispatch_queue_t queue = dispatch_get_main_queue(); // 创建串行队列 serial 串行 concurrent并发 queueSerial = dispatch_queue_create("searial.whenbar.com", DISPATCH_QUEUE_SERIAL); //创建并行队列 // 参1:const char *label 队列名称 // 参2:dispatch_queue_attr_t attr 队列类型 queueConcurrent = dispatch_queue_create("concurrent.whenbar.com", DISPATCH_QUEUE_CONCURRENT); } //1 获得主队列 -(void)runqueueMain { // 获取主队列 在主队列中的任务都会在主线程中执行。 dispatch_queue_t queueMain = dispatch_get_main_queue(); } //2. 创建串行队列 -(void)runqueueSerial { // GCD同步函数串行队列(立即执行,当前线程) // 参1: dispatch_queue_t queue 队列 // 参2: 任务 dispatch_sync(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); // 异步函数串行队列 (另开线程,多个任务按顺序执行) dispatch_async(queueSerial, ^{ dispatch_async(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); dispatch_async(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); dispatch_async(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); }); } //3. 创建并发队列 -(void)runqueueConcurrent { // 同步函数并行队列(立即执行,当前线程) dispatch_sync(queueConcurrent, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); // 异步函数并行队列 (另开线程,多个任务一起执行) dispatch_async(queueConcurrent, ^{ dispatch_async(queueConcurrent, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); dispatch_async(queueConcurrent, ^{ for (NSInteger i = 0; i < 6; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); dispatch_async(queueConcurrent, ^{ for (NSInteger i = 0; i < 7; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); } }); }); } //4. 创建全局队列 -(void)runqueueGlobal { // 获取全局队列 全局队列是并发队列 // 参1:队列的优先级 // 参2:0(以后可能用到的参数)//#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高\ #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)\ #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低\ #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 dispatch_queue_t queueGlobal = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); } // 主队列:(任何一个任务只要在主队列中,都会加入到主线程的队列中执行)
TIPS: 注意 GCD实现线程通信小项目:下载图片 代码如下: // 获取图片的url NSURL *url = [NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]; // 开启线程下载图片 dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; // 下载完成后返回主线程显示图片 dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; }); }); ———————————————————————————————————————— GCD其他常用函数
image
//----------------- 队列组 ----------------------------- //队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。下面是使用方法,这是一个很实用的功能。 -(void)rungroup { //1.创建队列组 dispatch_group_t group=dispatch_group_create(); //2.创建队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); //3.多次使用队列组的方法执行任务, 只有异步方法 //3.1.执行3次循环 dispatch_group_async(group,queue,^{ for (NSInteger i = 0; i< 3; i++){ NSLog(@"group-01 - %@", [NSThread currentThread]); } }); //3.2.主队列执行8次循环 dispatch_group_async(group, dispatch_get_main_queue(), ^{ for (NSInteger i=0;i<8;i++) { NSLog(@"group-02 - %@", [NSThread currentThread]); } }); //3.3.执行5次循环 dispatch_group_async(group, queue, ^{ for(NSInteger i=0;i<5;i++) { NSLog(@"group-03 - %@", [NSThread currentThread]); } }); //4.都完成后会自动通知 dispatch_group_notify(group,dispatch_get_main_queue(),^{ NSLog(@"完成 - %@", [NSThread currentThread]); }); } dispatch_barrier 栅栏 // 1.barrier : 在barrier前面的先执行,然后再执行barrier,然后再执行barrier后面的 barrier的queue不能是全局的并发队列 dispatch_queue_t queue = dispatch_queue_create("11", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ for (int i = 0; i < 100; i++) { NSLog(@"%@--1", [NSThread currentThread]); } }); dispatch_async(queue, ^{ for (int i = 0; i < 100; i++) { NSLog(@"%@--2", [NSThread currentThread]); } }); dispatch_barrier_async(queue, ^{ for (int i = 0; i < 100; i++) { NSLog(@"%@--3", [NSThread currentThread]); } }); dispatch_async(queue, ^{ for (int i = 0; i < 100; i++) { NSLog(@"%@--4", [NSThread currentThread]); } }); // dispatch_after 延迟执行 // 延迟执行 // 方法1 [self performSelector:@selector(run:) withObject:@"参数" afterDelay:2.0]; // 方法2 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ for (NSInteger i = 0; i < 100; i++) { NSLog(@"%@", [NSThread currentThread]); } }); // 方法3 [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run:) userInfo:nil repeats:NO]; dispatch_once 整个程序运行中执行一次 // 整个程序中只执行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 一次性代码 }); 思考题:以下函数输出的结果是什么?
image
以下的代码输出是什么呢
image
作用:实现某个类的单例对象 单例模式:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次) //--------------单例模式-------------------- #if __has_feature(objc_instancetype) #undef AS_SINGLETON #define AS_SINGLETON( ... ) \ - (instancetype)sharedInstance; \ + (instancetype)sharedInstance; #undef DEF_SINGLETON #define DEF_SINGLETON \ - (instancetype)sharedInstance \ { \ return [[self class] sharedInstance]; \ } \ + (instancetype)sharedInstance \ { \ static dispatch_once_t once; \ static id __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; } ); \ return __singleton__; \ } #undef DEF_SINGLETON #define DEF_SINGLETON( ... ) \ - (instancetype)sharedInstance \ { \ return [[self class] sharedInstance]; \ } \ + (instancetype)sharedInstance \ { \ static dispatch_once_t once; \ static id __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; } ); \ return __singleton__; \ } #else // #if __has_feature(objc_instancetype) #undef AS_SINGLETON #define AS_SINGLETON( __class ) \ - (__class *)sharedInstance; \ + (__class *)sharedInstance; #undef DEF_SINGLETON #define DEF_SINGLETON( __class ) \ - (__class *)sharedInstance \ { \ return [__class sharedInstance]; \ } \ + (__class *)sharedInstance \ { \ static dispatch_once_t once; \ static __class * __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[[self class] alloc] init]; } ); \ return __singleton__; \ } #endif // #if __has_feature(objc_instancetype) #import "gcdfunViewController.h" #pragma mark - 单例模式(责任编辑:好模板) |