05-多线程(1)

0708-GCD单例模式

1、概述(01-多线程的基本概念)

  • 多线程如果掌握得不好对一些性能方面的东西会做的不好
  • 一个两到三年的IOS开发者最常问:
  • 事件处理:响应者链条
  • Runtime
  • RunLoop:多线程
  • 一个运行中的程序就是一个进程,程序要执行任务就必须开辟线程来执行,一个进程至少有一条线程
  • 一条线程对象即使他是局部变量,他会在任务完成时自动销毁
  • 一条线程中多个任务的执行是串行的
  • 一个进程可以开辟多条线程,每条线程并行执行不同的任务
  • 多线程开发的缺点
  • CPU需要调度N多线程会消耗大量CPU资源
  • 每条线程被调度执行的次数降低(线程执行效率降低)
  • 创建线程是有开销的,iOS下主要成本包括:内核数据结构(大约1KB)、栈空间(子线程512KB、主线程1MB,也可以使用-setStackSize:设置,但必须是4K的倍数,而且最小是16K),创建线程大约需要90毫秒的创建时间
  • 程序设计更加复杂:比如线程之间的通信、多线程的数据共享
  • 多线程开发的优点
  • 适当提高程序执行效率
  • 每条线程被调度执行的次数降低(线程执行效率降低)
  • 主线程的作用
  • 显示\刷新UI界面
  • 处理UI事件(比如点击事件、滚动事件、拖拽事件等)

2、iOS中多线程的实现方案(03-多线程的实现方案)

05-多线程(1)_第1张图片

3、线程的状态(06-线程的状态)

05-多线程(1)_第2张图片

4、线程之间的通信方式(08-线程间的通信)

  • NSThread
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self performSelectorInBackground:@selector(download3) withObject:nil];
}
 - (void)download3
{
    // 图片的网络路径
    NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
    
    // 加载图片
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    // 生成图片
    UIImage *image = [UIImage imageWithData:data];
    
    // 回到主线程,显示图片
    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
//    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
}
  • GCD
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
        
        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成图片
        UIImage *image = [UIImage imageWithData:data];
        
        // 回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
        });
    });
}
  • NSPort(端口),比较复杂、现在很少用
  • NSMessagePort;
  • NSMachPort;

5、各种队列的执行效果(10-gcd的各种队列)

6、GCD的其他常用函数(12-gcd常用函数)

  • dispatch_barrier_async
 - (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });
    //先执行barrier之前的,再执行barrier,最后执行barrier之后的,需要注意一点的是queue不能是全局的并发队列
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}
  • 延时执行
  • 调用NSObject的方法
  • 使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 2秒后异步执行这里的代码...
});
  • 定时器
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
  • 一次性代码
 - (void)once
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"------run");
    });
}
  • 快速迭代(利用多线程并发执行循环遍历)
/**
 * 使用GCD快速迭代剪切
 */
 - (void)apply
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSString *from = @"/Users/xiaomage/Desktop/From";
    NSString *to = @"/Users/xiaomage/Desktop/To";
    
    NSFileManager *mgr = [NSFileManager defaultManager];
    NSArray *subpaths = [mgr subpathsAtPath:from];
    
    dispatch_apply(subpaths.count, queue, ^(size_t index) {
        NSString *subpath = subpaths[index];
        NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
        NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
        // 剪切
        [mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil];
        
        NSLog(@"%@---%@", [NSThread currentThread], subpath);
    });
}
/**
 * 传统文件剪切
 */
 - (void)moveFile
{
    NSString *from = @"/Users/xiaomage/Desktop/From";
    NSString *to = @"/Users/xiaomage/Desktop/To";

    NSFileManager *mgr = [NSFileManager defaultManager];
    NSArray *subpaths = [mgr subpathsAtPath:from];

    for (NSString *subpath in subpaths) {
        NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
        NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 剪切
            [mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil];
        });
    }
}
  • 队列组
 - (void)group
{
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建一个队列组
    dispatch_group_t group = dispatch_group_create();
    
    // 1.下载图片1
    dispatch_group_async(group, queue, ^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
        
        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成图片
        self.image1 = [UIImage imageWithData:data];
    });
    
    // 2.下载图片2
    dispatch_group_async(group, queue, ^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
        
        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成图片
        self.image2 = [UIImage imageWithData:data];
    });
    
    // 3.将图片1、图片2合成一张新的图片
    dispatch_group_notify(group, queue, ^{
        // 开启新的图形上下文
        UIGraphicsBeginImageContext(CGSizeMake(100, 100));
        
        // 绘制图片
        [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
        [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];
        
        // 取得上下文中的图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        // 结束上下文
        UIGraphicsEndImageContext();
        
        // 回到主线程显示图片
        dispatch_async(dispatch_get_main_queue(), ^{
            // 4.将新图片显示出来 
            self.imageView.image = image;
        });
    });
}

7、单例模式(14-gcd实现单例模式)

在IOS里面单例有几种实现方式,最常用的就是GCD来实现。什么是设计模式?长期积累的一种经验。

  1. 步骤(ARC)
  • static id _instance;
  • 重写allocWithZone(重新alloc)
  • 给外界重写一个公用方法+ (instancetype)sharedInstance
  • 重新copyWithZone(重新copy方法)
  1. 重新alloc方法只需要重写allocWithZone方法
 + (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _person = [super allocWithZone:zone];
    });
    return _person;
}
  1. 在一个专门的h文件里用宏定义单例
// .h文件
#define XMGSingletonH(name) + (instancetype)shared##name;
/ .m文件
#define XMGSingletonM(name) \
static id _instance; \
 \
 + (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [super allocWithZone:zone]; \
    }); \
    return _instance; \
} \
 \
 + (instancetype)shared##name \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [[self alloc] init]; \
    }); \
    return _instance; \
} \
 \
 - (id)copyWithZone:(NSZone *)zone \
{ \
    return _instance; \
}
//static 让外界即使通过extern都不能访问

你可能感兴趣的:(05-多线程(1))