多线程的优缺点:

优点
1. 能适当提高程序的执行效率
2. 能适当提高资源利用率(CPU,内存利用率)

缺点
1. 创建线程是有开销的,iOS下主要成本包括:内核数据结构(大约1KB),栈空间(子线程512KB,主线程1MB,也可以使用-setStackSize;设置),但必须是4K的倍数,而且最小是16K,创建线程大约需要90毫秒的创建时间。
2. 如果开启大量的线程,会降低程序的性能
3. 线程越多,CPU在调度线程上的开销越大(手机发烫,耗电增多)

多线程在iOS开发中的应用

什么是主线程?
- 一个iOS程序运行后,默认会开启1条线程,成为“主线程”或“UI线程”

主线程的主要作用
- 显示|刷新UI界面
- 处理UI事件(比如点击事件,滚动事件,拖拽事件等)

主线程的使用注意

  • 别将比较耗时的操作放在主线程中
  • 耗时操作会卡住主线程,严重影响UI的流程度,给用户一种”卡”的坏体验

iOS中多线程的实现方案

ios 的多线程和异步 ios多线程优缺点_ios 的多线程和异步

pthread的简单使用

#import "ViewController.h"
#import <pthread.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];  
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self pthreadDemo];
}

-(void)pthreadDemo{
    //注意:多线程开发中,千万不要相信一次的执行结果!!!
    /*
     pthread 是属于 POSIX 多线程开发框架
     参数:
     1.指向线程代号的指针
     2.线程的属性
     3.指向函数的指针
     4.传递给该函数的参数

     返回值
     -如果是0,表示正确
     -如果非0,表示错误代码
     void*  (*)(void *)
     返回值  (函数指针) (参数)
     void* 和OC中的id是等价的!
     */
    NSString * str = @"hello wt";
    pthread_t threadId;
    /*
     -在 ARC 开发中,如果涉及到和C语言中的相同的数据类型进行转换,需要使用__bridge "桥接"
     -在 MRC 不需要
     */
    int result = pthread_create(&threadId, NULL,&demo, (__bridge void *)(str));
    if(result == 0){
        NSLog(@"OK");
    }else{
        NSLog(@"error %d",result);
    }
}
//定义一个函数
void * demo(void * param){
    NSLog(@"%@ %@",[NSThread currentThread],param);
    return  NULL;
}
@end

NSThread

#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self threadDemo3];
}
-(void)threadDemo3{
    //number=1
    NSLog(@"A---%@",[NSThread currentThread]);
    //InBackground 就是在后台(子线程)运行!!
    //是NSObject的分类,意味着所有的继承NSObject的都可以使用这个方法
    //非常方便,不用NSThread对象
    [self performSelectorInBackground:@selector(demo:) withObject:@"background"];
    //number=1
    NSLog(@"B---%@",[NSThread currentThread]);
}
-(void)threadDemo2{
    //number=1
    NSLog(@"A---%@",[NSThread currentThread]);
    //detach => 分离(立刻启动子线程)
    [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"];
    //number=1
    NSLog(@"B---%@",[NSThread currentThread]);
}
-(void)threadDemo1{
    NSLog(@"A--------------");
    //创建一个NSThread
    NSThread * thread =[[NSThread alloc]initWithTarget:self selector:@selector(demo:) object:@"Thread"];
    //启动线程
    [thread start];
    for (int i=0; i<10; i++) {
        NSLog(@"%d",i);
    }
    NSLog(@"B--------------");
}
-(void)demo:(id)obj{
    for (int i=0; i<2; i++) {
        //number !=1
      NSLog(@"C--------------%@",[NSThread currentThread]);
    }
}
@end

多线程加载网络图片

#import "ViewController.h"

@interface ViewController ()<UIScrollViewDelegate>

@property(nonatomic,strong)UIScrollView * scrollView;
@property(nonatomic,weak)UIImageView *imageView;
@property(nonatomic,strong)UIImage * image;
/**
 问题一.为什么scrollView用strong修饰?imageView用week?
 */

@end

@implementation ViewController

/**
 加载视图结构,纯代码开发
 功能  SB&XIB 是一样的
 如果重写了这个方法,SB和XIB都无效
 */
-(void)loadView{
    //搭建界面
    self.scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.view  =self.scrollView;
    //MARK:-设置缩放属性
    self.scrollView.delegate = self;
    self.scrollView.minimumZoomScale = 0.5;
    self.scrollView.maximumZoomScale = 2.0;

    //imageView
    UIImageView * iv =[[UIImageView alloc]init];
    //会调用view的getter方法。loadView方法在执行的过程中,如果self.view == nil,会自动调用loadView加载
    [self.view addSubview:iv];
    self.imageView = iv;
}

/**
 视图加载完毕
 一般做初始化工作
 */
- (void)viewDidLoad {
    [super viewDidLoad];
//    [self downloadImage];
    NSThread * t1 =[[NSThread alloc]initWithTarget:self selector:@selector(downloadImage) object:nil];
    [t1 start];
}

//MARK: - 下载图片
-(void)downloadImage{
    NSLog(@"%@",[NSThread currentThread]);

    //NSUTL -> 统一资源定位符,每一个URL,对应着一个网络资源
    NSURL * url =[NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1525326853527&di=56bda83da629c944572273eb3793ede9&imgtype=0&src=http%3A%2F%2Fscimg.jb51.net%2Fallimg%2F170209%2F106-1F20916102V08.jpg"];

    //下载图片(在网络上传输的所有数据都是二进制)
    //为什么是二进制:因为物理层是网线,网线里面是电流,电流有高低电频,高低电频表示二进制.数字信号转模拟信号转电信号
    NSData * data =[NSData dataWithContentsOfURL:url];

    //将二进制数据转成图片并且设置图片
    //提示:不是所有的更新UI在后台线程支持都会有问题
    //重点提示:不要去尝试在后台线程更新UI,出了问题是非常诡异的
//    self.image =[UIImage imageWithData:data];

    //在UI线程去更新UI

    /**
     *1.SEL:在主线程执行的方法
     *2.传递给方法的参数
     *3.是否让当前线程等待(注意:如果当前线程是主线程,YES没有用)
     */
    //线程间通信
    [self performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageWithData:data] waitUntilDone:NO];
    NSLog(@"come here");
}
-(void)setImage:(UIImage *)image{
    _image =image;
    NSLog(@"更新UI在%@",[NSThread currentThread]);
    //直接将图片设置到控件上
    self.imageView.image = image;
    //让imageView和image一样大
    [self.imageView sizeToFit];
    //指定scrollView的contentSize
    self.scrollView.contentSize=image.size;
}

#pragma mark - <UIScrolView代理>
//告诉ScrollView 缩放哪个View
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return self.imageView;
}

/** 二维空间中, 平面中,表示一个集合图形 x y width height
  *transform 矩阵
 *struct CGAffineTransform {
   CGFloat a(缩放比例), b, c, d(缩放比例);
   CGFloat tx(位移), ty(位移);
 };
 */
-(void)scrollViewDidZoom:(UIScrollView *)scrollView{
    NSLog(@"%@",NSStringFromCGAffineTransform(self.imageView.transform));
}

@end