1.多线程-NSThread

1.在主线程执行多次NSLog模拟耗时操作

结果,卡住主线程

解决方案: performSelectorInBackground让程序在后台执行
 
2.pthread的使用
开辟子线程,执行一个函数
__bridge桥接,OC对象和C指针之间的转换
{  /*
        参数1:线程的编号(地址)
        参数2:线程的属性 NULL nil(oc)
        参数3:要调用的函数 void *  (*)  (void *)
        参数4:给要调用的函数传递的参数
     */
    //开辟新的线程
    pthread_t ID;
    NSString *str = @"ls";
    //__bridge桥接 类型转换(oc - 》c)
    //MRC 谁创建,谁释放
    //ARC 自动管理
    int result = pthread_create(&ID, NULL, demo, (__bridge void *)(str));
    //result 0 代表成功 其他代表失败
    if (result == 0) {
        NSLog(@"成功");
    }else
    {
        NSLog(@"失败");
    }
    
}
/**
    pthread调用的函数
 */
void * demo(void * param)
{
    NSString *Str = (__bridge NSString *)(param);
    //获取当前的代码执行在哪个线程当中,获取当前线程
    NSLog(@"%@ %@",Str,[NSThread currentThread]);
    return NULL;
}

3.NSThread的3种使用方式

{   //创建
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(demo) object:nil];
    //调用
    [thread start];
    
//    //方式2
    [NSThread detachNewThreadSelector:@selector(demo) toTarget:self withObject:nil];
    
    //方式3
    [self performSelectorInBackground:@selector(demo) withObject:nil];
    
    //传递参数
    [self performSelectorInBackground:@selector(demo2:) withObject:@"HM"];
    
}
- (void)demo2:(NSString *)str
{
    NSLog(@"%@ %@",str,[NSThread currentThread]);
}
/**
    要调用的方法
 */
- (void)demo
{
    NSLog(@"%@",[NSThread currentThread]);
}

4.线程的生命周期

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //新建状态
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(demo) object:nil];
    //就绪状态
    [thread start];
    
    //运行状态:系统控制的
    
    
}
- (void)demo
{
    for (int i = 0; i <20; i++) {
        
        if (i == 5) {
            //阻塞状态
            //让当前的线程睡一段时间
            [NSThread sleepForTimeInterval:3];
        }else if (i == 10)
        {
            //死亡状态
            [NSThread exit];
        }
        NSLog(@"%d",i);
    }
}

5.NSThread的属性,可以设置属性的名称、优先级

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //线程属性
    //主线程占用的内存空间
    NSLog(@"%zd",[NSThread currentThread].stackSize/1024);
    //创建线程1
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(demo) object:nil];
    //设置线程名称
    thread.name = @"t1";
    //设置线程的优先级 参数的取值范围 0-1  0是优先级最低的,1是优先级最高 默认的是0.5
    [thread setThreadPriority:1.0];
    [thread start];
    
    //创建线程2
    NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(demo) object:nil];
    //设置线程名称
    thread2.name = @"t2";
    [thread2 setThreadPriority:0.0];
    [thread2 start];
    
    //设置线程的优先级不能绝对保证线程优先执行,但是线程被调用的概率提高
    
}
- (void)demo
{
    
    //子线程占用的内存空间
    NSLog(@"demo  %zd",[NSThread currentThread].stackSize/1024);
//    NSLog(@"%@",[NSThread currentThread]);
    for (int i = 0; i < 10; i++) {
        NSLog(@"%d %@",i,[NSThread currentThread].name);
        
    }
    
}

6.线程间资源抢夺的时候,需要加互斥锁(锁住一个对象)

#import "ViewController.h"

@interface ViewController ()
//总票数
@property(nonatomic,assign)int totalTickets;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置票数为20
    self.totalTickets = 20;
    
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //窗口1 模拟卖票
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    thread.name = @"t1";
    [thread start];
    
    
    //窗口2 模拟卖票
    
    NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    thread2.name = @"t2";
    [thread2 start];
}
/**
    卖票
 */
- (void)sellTickets
{
    while (YES) {
        //被加锁的对象
        @synchronized(self) {
            //查询剩余的票数,判断
            if (self.totalTickets > 0) {
                self.totalTickets = self.totalTickets - 1;
                NSLog(@"剩余%d票 %@",self.totalTickets,[NSThread currentThread].name);
            }else
            {
                NSLog(@"票卖完了,回不了家,走路回家");
                break;
            }
        }
       
    }
}

7.异步下载图片,在子线程下载图片,在主线程更新UI

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //网络图片下载
    /*
            1.不能把耗时操作放到主线程中,开辟新的线程
            2.刷新ui一定要在主线程
//     http://g.hiphotos.baidu.com/image/pic/item/f31fbe096b63f624cd2991e98344ebf81b4ca3e0.jpg
     */
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImg) object:nil];
    [thread start];
    
    
}
/**
    下载图片
 */
- (void)downloadImg
{
    NSLog(@"downloadImg %@",[NSThread currentThread]);
    //获取链接地址
    NSURL *url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f31fbe096b63f624cd2991e98344ebf81b4ca3e0.jpg"];
    //转化NSData类型
    NSData *data = [NSData dataWithContentsOfURL:url];
    //转化成UIImage
    UIImage *img = [UIImage imageWithData:data];
    
    /*
        参数1:主线程要调用的方法
        参数2:给调用的方法传递的参数
        参数3:是否等待当前代码执行完毕再来执行下面的代码
     */
    [self performSelectorOnMainThread:@selector(updataUI:) withObject:img waitUntilDone:YES];
    NSLog(@"end");
    
}
/**
    刷新ui ui刷新必须放到主线程里面
 */
- (void)updataUI:(UIImage *)img
{
    NSLog(@"updataUI %@",[NSThread currentThread]);
    [NSThread sleepForTimeInterval:3];
    self.HMImageView.image = img;
}
原文地址:https://www.cnblogs.com/fanglove/p/5215180.html