网络多线程学习笔记
一 .NSThread
1.NSThread的三种创建方式
1>直接创建!
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"Thread"];
[thread start];
2>detachNewThreadSelector
*这是在后台执行的方法
[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"];
3>performSelectorInBackground:
- 是 NSObject 的一个分类方法,意味着所有的 NSObject 都可以使用此方法,在其他线程执行方法!
- 特点:没有thread字眼,一旦制定,就会立即在后台线程执行 selector 方法
- performSelectorInBackground 隐式的多线程方法,这种方法,在使用的时候更加灵活!
[对象 performSelectorInBackground:@selector(loadData) withObject:nil];
2.线程的状态
注意:在终止线程之前,应该注意释放之前分配的对象!
如果是 ARC 开发,需要注意,清理 C 语言框架创建的对象!否则会出现内存泄漏!
3.NSThread属性
* t1.name = @"Thread A";
* 用途:在大的商业项目中,通常希望程序崩溃的时候,能够获取到程序准确执行所在的线程!
* t1.threadPriority = 0.1;
* 优先级,是一个浮点数,从0~1.0,1.0表示优先级最高,默认优先级是0.5!优先级只是保证 CPU 调度的可能性会高!
* ![NSThread isMainThread
* 判断是否是主线程
4.多线程的目的
- 多线程的目的:将耗时的操作放在后台,不阻塞主线程和用户的交互!
- 个人建议,在开发的时候,不要修改优先级!优先级翻转!
- 多线程开发,有一个原则:尽量简单!
5.多线程会出现的问题
- 资源抢夺
- 互斥锁 - 保证锁内的代码,同一时间,只有一条线程能够执行!
- 多线程的目的:耗时的操作放在后台
- 多线程的优点:通过并发提高程序的执行效率!
- 互斥锁的锁定范围,应该尽量小,锁定范围越大,效率越差!
实际上,原子属性内部也有一把锁,自旋锁
“`
- 自旋锁 & 互斥锁
- 共同点
都能够保证同一时间,只有一条线程执行锁定范围的代码
- 不同点
互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒
自旋锁:如果发现有其他线程正在执行锁定的代码,线程会用死循环的方式,一直等待锁定代码执行完成!
自旋锁更适合执行非常短的代码!
- 自旋锁 & 互斥锁
无论什么锁,都是要付出代价的!
“`
6.线程间通信
performSelectorOnMainThread "线程间通讯"
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
1. 在主线程执行的方法
2. 传递给方法的参数
3. 是否等待被调用方法执行完成,有可能也会等待调用方法的执行完成!几率极少!
7.一些问题
- 问题1:为什么scrollView是strong,imageView是weak?
在 OC 中如果一个对象没有其他对象做强引用,会被立即释放!
问题2: UIImage & UIImageView有什么区别
- UIImage 是图像 - 照片
- UIImageView 是视图 - 相框
8.定时器
以下两句两种添加时钟的方法是等价的
1. NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
// 加入运行循环
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
2. [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
* NSDefaultRunLoopMode - 时钟,网络事件;
* NSRunLoopCommonModes - 用户交互;
9. 运行循环
- 保证程序不退出!
- 负责监听事件,监听 iOS 中所有的事件:触摸,时钟,网络事件
- 如果没有事件发生,会让程序进入休眠状态
10.开发多线程程序的步骤
- 保证单个线程执行正常!
- 每一个售票逻辑(窗口)应该把所有的票卖完
- 添加线程
二 .02 -GCD
- GCD 核心概念:将任务添加到队列,指定任务执行的方法
- 任务
-使用 block 封装
-block就是一个提前准备好的代码块,在需要的时候执行
- 队列(负责调度任务)
- 串行队列:一个接一个的调度任务
- 并发队列:可以同时调度多个任务
- 主队列: 专门用来在主线程上调度任务的"队列"
主队列不能在其他线程中调度任务!
如果主线程上当前正在有执行的任务,主队列暂时不会调度任务的执行!
注意:主队列不是主线程
- 异步任务,会在主线程的方法执行完成后,被调度
- 同步任务,会造成死锁
- 全局队列,系统提供给程序员,方便程序员使用的全局队列
有关服务质量问题,使用以下代码能够做到 iOS7 & iOS8 的适配
dispatch_get_global_queue(0, 0);
- 执行任务的函数
- 同步执行:当前指令不完成,就不会执行下一条指令
- 异步执行:当前指令不完成,同样可以执行下一条指令
异步是多线程的代名词
小结:
- 开不开线程,取决于执行任务的函数,同步不开,异步开
- 开几条线程,取决于队列,串行开一条,并发开多条(异步)
同步任务在多线程中的用处:
- 可以队列调度多个异步任务前,指定一个同步任务,让所有的异步任务,等待同步任务执行完成,这就是所谓的依赖关系!
全局队列 & 并发队列
1> 名称,并发队列有名称,适合于商业级软件跟踪错误报告!
2> release, 在 MRC 开发时,并发队列需要使用
dispatch_release(q);
结论:目前绝大多数的软件都会使用全局队列。比较优秀的第三方框架会使用自定义的并发队列!
日常使用:用全局!
全局队列 & 串行队列选择
全局队列:并发,能够调度多个线程,执行效率高
-费电
串行队列:一个接一个,只能够开启一条线程,执行效率低(斯坦福大学)
-如果任务之间需要依赖,使用串行队列
-省电,省钱,省流量
判断依据:用户的上网方式
-WIFI,可以多开线程,6条
-3G/4G,尽量少开线程,2~3条
- 全局对列的参数
- dispatch_queue_t q = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
***<参数>
1. 涉及到系统适配
iOS 8 服务质量(让线程响应的更快还是更慢&#x