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; }
我要青春像陈孝正一样,不能有一毫米的误差!
我要青春像合伙人一样,为了自尊而战!