网络多线程3
2016-12-13 00:00
344 查看
NMTDAY03
1.GCD的高级功能
1.1GCD阻塞(Barrier)
1.2GCD延迟操作
1.3GCD一次性执行once
1.4GCD调度组group
1.5GCD单例设计模式Singleton
1.5.1两种方式创建单例
1.5.1懒汉式单例(lazyinitialization)
1.5.2饿汉式单例(eagerinitialization)
2.NSOperation
2.1NSInvocationOpearion
2.2NSBlockOperation
2.3NSOperation和GCD的对比
3.NSOperation的高级功能
3.1队列的最大并发数
3.2队列的暂停、继续、取消
3.2.1队列暂停
3.2.2队列继续
3.2.3队列取消
3.3操作间的依赖关系
3.4.操作的优先级和监听操作执行完成的回调
4.列表异步加载网络图片
4.1SDWebImage加载网络图片
4.2NSOperation加载网络图片
5.GitHub初体验
6.AFN请求json数据
7.SDWebImage
一次性执行Once
延迟操作After
调度组Group
barrier使用的时候规定要使用自定义的并行队列
大部分情况下都是正确的,但是不能绝对信任。
使用代码块
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(1*NSEC_PER_SEC)),dispatch_get_main_queue(),^{
NSLog(@"iamstarting");
});
自己手写
//dispatch_time_twhen:延迟多久开始执行,可以精确到纳秒
//dispatch_queue_t:在那个队列执行任务
//参数三:执行的任务代码块
dispatch_after(dispatch_time_twhen,dispatch_queue_t_Nonnullqueue,^{
code
})
//dispatch_time_twhen:延迟多久开始执行,可以精确到纳秒
//dispatch_queue_t:在那个队列执行任务
//参数三:执行的任务代码块
dispatch_time_twhen=dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0*NSEC_PER_SEC));
dispatch_queue_tqueue=dispatch_get_global_queue(0,0);
dispatch_block_tblock=^{
NSLog(@"I'mlate:%@",[NSThreadcurrentThread]);
};
dispatch_after(when,queue,block);
NSLog(@"~~~~end~~~~~");
dispatch_once_t内部有一把锁,是能够保证线程安全.而且是苹果公司推荐使用的.
名词解释:线程安全
线程安全:这个任务在同一时
7ff0
刻有且只能被一个线程执行。
线程不安全:是说这个任务在同一时刻可以被多个线程执行。
在开发中,有些代码只想就只执行一次.典型的应用场景就是设计单例模式.
dispatch_once_t能够确保只执行一次的原理:
onceToken有个初始值,当第一次执行时,判断是否是初始值,如果是初始值就执行函数内部的代码。
执行结束之前,修改onceToken初始值。
第二次执行的时候,因为onceToken已经不再是初始值,所以就不会再次执行了。
staticdispatch_once_tonceToken;
NSLog(@"%ld",onceToken);
dispatch_once(&onceToken,^{
NSLog(@"hello");
});
使用场景:监听一组异步任务是否执行结束,如果执行结束就能够得到统一的通知.
//dispatch_group_t:调度组
//dispatch_queue_t:队列
//block:任务
dispatch_group_async(dispatch_group_t_Nonnullgroup,dispatch_queue_t_Nonnullqueue,<#^(void)block#>)
enter和leave都是成对儿出现的。
enter如果比leave多,那就永远不会被通知,监测实效。
enter如果比leave少,程序直接crash。
//下载三首歌曲ABC,歌曲的下载顺序不做要求,但是要知道什么时候下载完成
-(void)downloadSongs{
//dispatch_group_t:调度组
//dispatch_queue_t:队列
//block:任务
dispatch_group_tgroup=dispatch_group_create();
dispatch_queue_tqueue=dispatch_get_global_queue(0,0);
dispatch_group_enter(group);
dispatch_group_async(group,queue,^{
NSLog(@"A歌曲下载完毕%@",[NSThreadcurrentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group,queue,^{
NSLog(@"B歌曲下载完毕%@",[NSThreadcurrentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group,queue,^{
NSLog(@"C歌曲下载完毕%@",[NSThreadcurrentThread]);
dispatch_group_leave(group);
});
//所有歌曲下载完之后,通知用户ABC都下载完毕了。
dispatch_notify(group,dispatch_get_main_queue(),^{
NSLog(@"WellDone.%@",[NSThreadcurrentThread]);
});
}
有一个全局访问点(供全局实例化单例的类方法)
单例保存在静态存储区
在内存有且只有一份
生命周期跟APP一样长
场景:
例如QQ音乐播放器,只有一个播放器,播放所有的音频。
数据库大量的读写操作
工程里面常用的工具类:获取沙盒路径的类、处理网络数据的类、用户登录
系统提供的单例:
[NSUserDefaultsstandardUserDefaults];perfermance设置
[UIApplicationsharedApplication];Application
[NSNotificationCenterdefaultCenter];通知中心
[NSFileManagerdefaultManager];文件管理器
还有日历,等等
注意:单例不要滥用,因为单例的生命周期跟APP一样,也会占用内存。
潜规则系统一般定义,单例都是以default,shared开通。
命名规则:shared+类名称
+(instancetype)sharedNetworkTool
现在我们的目的是类无论创建多少次,都只分配一次存储空间,而分配存储空间的操作是在alloc:中执行,所以我们要重写类中的alloc:类方法
在重写alloc:过程中,我们发现有个allocWithZone:方法。alloc:方法内部最终会去调用allocWithZone:方法来分配存储空间,所以为了能更深层控制,我们直接重写allocWithZone:方法。
+(instancetype)alloc
+(instancetype)allocWithZone:(struct_NSZone*)zone
为了让单例严谨一点,我们还要考虑copy这种情况,所以我们还要重写copy和mutableCopy。要重写copy和mutableCopy方法,必须先遵守协议。
@interfaceNetworkTool()<NSCopying,NSMutableCopying>
-(id)copyWithZone:(NSZone*)zone
{
//直接返回变量即可,因为只有创建了对象,才能使用copy方法
return_instance;
}
-(id)mutableCopyWithZone:(NSZone*)zone
{
return_instance;
}
在学习多线程之前,写单例的方法:BUT,在多线程下是错误的,因为线程不安全。
+(instancetype)allocWithZone:(struct_NSZone*)zone{
staticid_instance;
if(!_instance){
_instance=[superallocWithZone:zone];
}
return_instance;
}
方式一:加线程锁
+(instancetype)allocWithZone:(struct_NSZone*)zone{
staticid_instance;
@synchronized(self){
if(!_instance){
_instance=[superallocWithZone:zone];
}
}
return_instance;
}
方式二:不需要做判断了,因为dispatch_once只能执行一次,并且线程安全。推荐使用。这个就是专门为单例设计的,高效+安全。
+(instancetype)allocWithZone:(struct_NSZone*)zone{
staticid_instance;
staticdispatch_once_tonceToken;
dispatch_once(&onceToken,^{
_instance=[superallocWithZone:zone];
});
return_instance;
}
initialize方法创建单例。
initialize会在类第一次被使用时调用
initialize调用是线程安全的。
+(void)initialize
{
_instance=[[selfalloc]init];
}
//饿汉式单例
+(instancetype)sharedNetworkManager
{
return_instance;
}
拓展:
饿汉模式、懒汉模式的优缺点
饿汉式在类创建的同时,已经创建好对象,以后不再改变,所以天生就是线程安全的
懒汉模式,如果需要线程安全还需要借助线程锁或者dispatch_once。无论是哪个方法,对性能都有降低,而实际99%的情况下都不需要同步。
使用起来比GCD更加简单(面向对象)
提供了一些用GCD不好实现的功能.
苹果推荐使用,使用NSOperation不用关心线程以及线程的生命周期.
NSOperation是个抽象类,无法直接使用.因为方法只有声明没有实现。
作为父类使用的.约束子类共有的属性和方法.
子类:
2.1.NSInvocationOperation//系统提供的
2.2.NSBlockOperation//系统提供的
2.3.自定义NSOperation
操作默认是异步的.
队列:NSOperationQueue
队列默认是并发的.
核心:
4.1.GCD的核心:将任务添加到队列中
4.2.OP的核心:将operation添加到队列中
使用步骤:
先将需要执行的operation封装到一个NSOperation对象中.创建NSOperation对象.(其实是封装到NSOperation的子类中去。)
将NSOperation对象添加到NSOperationQueue中.
NSOperationQueue会自动将NSOperation取出来.
将取出的NSOperation封装的操作自动放到一条对应的新线程中执行.
操作添加到队列
使用start的方法,会在当前线程执行@selector方法。不会开启新线程。
正确开启新线程的姿势
-(void)invocationOperation{
//将op封装成NSInvocationOperation
NSInvocationOperation*invocationOperation=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(invocationMethod)object:nil];
//start也会执行,但是不会开启新线程
//[invocationOperationstart];
//创建NSOperationQueue
NSOperationQueue*queue=[[NSOperationQueuealloc]init];
//将op添加入队列
[queueaddOperation:invocationOperation];
}
NSOperationQueue只有一种类型.就是并发队列.
在实际开发时,如果要使用到NSOperationQueue,可以直接定义成全局的队列
使用start的方法,会在当前线程执行@selector方法。不会开启新线程。
继续/暂停/取消全部
操作的优先级和监听操作执行完成的回调
操作间依赖关系
@propertyNSIntegermaxConcurrentOperationCount;
限制同时执行的任务数.
比如,最大并发数设置成3,队列就会保证只同时执行3个任务.从而间接的控制了线程的数量.
线程可以复用.而且在线程回收的间隙可以及时的准备线程保证并发性.
注意:队列最大并发数不是线程数!!!
准备队列:也可以采用成员变量的方式定义
-(BOOL)isSuspended;暂停和继续队列的属性.
YES代表暂停队列,NO代表恢复队列.
cancelAllOperations:取消队列中的全部操作.
cancel:取消队列中的单个操作.
队列处于暂停状态时,是没有办法修改operationCount数值。
operationCount:操作计数,没有执行和没有执行完的操作,都会计算在操作计数之内
[self.queuesetSuspend:YES];
正在执行的操作,没有办法暂停。
[self.queuesetSuspend:NO];
cancelAllOperations方法,队列中的操作,都会被移除,正在执行的操作除外.
正在执行的操作取消不了,如果要取消,需要自定义NSOperation.
队列取消全部操作时,会有一定的时间延迟
操作间可以跨队列建立依赖关系
要将操作间的依赖建立好了之后,再添加到队列中
先建立操作依赖关系
再把操作添加到队列
//登录-》付费-》下载
-(void)downloadSongs{
//创建OP
NSBlockOperation*login=[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"login");
}];
NSBlockOperation*pay=[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"payment");
}];
NSBlockOperation*download=[NSBlockOperationblockOperationWithBlock:^{
NSLog(@"download");
}];
//添加依赖关系
[downloadaddDependency:pay];
[payaddDependency:login];
//即便op在不同的队列里面,依赖关系依然存在
NSOperationQueue*queue=[[NSOperationQueuealloc]init];
[queueaddOperations:@[login,download]waitUntilFinished:NO];
[[NSOperationQueuemainQueue]addOperation:pay];
NSLog(@"WellDone");
}
NSBlockOperation*op=[NSBlockOperationblockOperationWithBlock:^{
for(inti=0;i<10;i++){
NSLog(@"op%d",i);
}
}];
//监听操作执行完成
[opsetCompletionBlock:^{
NSLog(@"------CompletionBlock-------");
}];
定义获取json文件的主方法
参数一:URL地址
参数二:不需要
参数三:下载进度
参数四:成功的block
参数五:失败的block
使用block字典转模型
数据加载之后,需要刷新页面
1.GCD的高级功能
1.1GCD阻塞(Barrier)
1.2GCD延迟操作
1.3GCD一次性执行once
1.4GCD调度组group
1.5GCD单例设计模式Singleton
1.5.1两种方式创建单例
1.5.1懒汉式单例(lazyinitialization)
1.5.2饿汉式单例(eagerinitialization)
2.NSOperation
2.1NSInvocationOpearion
2.2NSBlockOperation
2.3NSOperation和GCD的对比
3.NSOperation的高级功能
3.1队列的最大并发数
3.2队列的暂停、继续、取消
3.2.1队列暂停
3.2.2队列继续
3.2.3队列取消
3.3操作间的依赖关系
3.4.操作的优先级和监听操作执行完成的回调
4.列表异步加载网络图片
4.1SDWebImage加载网络图片
4.2NSOperation加载网络图片
5.GitHub初体验
6.AFN请求json数据
7.SDWebImage
1.GCD的高级功能
阻塞Barrier一次性执行Once
延迟操作After
调度组Group
1.1GCD阻塞(Barrier)
注意:barrier使用的时候规定要使用自定义的并行队列
大部分情况下都是正确的,但是不能绝对信任。
1.2GCD延迟操作
延迟操作:‘dispatch_after’这个函数默认是异步执行的使用代码块
自己手写
1.3GCD一次性执行once
名词解释:线程安全
线程安全:这个任务在同一时
7ff0
刻有且只能被一个线程执行。
线程不安全:是说这个任务在同一时刻可以被多个线程执行。
在开发中,有些代码只想就只执行一次.典型的应用场景就是
执行结束之前,修改
第二次执行的时候,因为
1.4GCD调度组group
调度组中的所有异步任务执行结束之后,会得到统一的通知.使用场景:监听一组异步任务是否执行结束,如果执行结束就能够得到统一的通知.
1.5GCD单例设计模式Singleton
单例设计模式的特点:有一个全局访问点(供全局实例化单例的类方法)
单例保存在静态存储区
在内存有且只有一份
生命周期跟APP一样长
场景:
例如QQ音乐播放器,只有一个播放器,播放所有的音频。
数据库大量的读写操作
工程里面常用的工具类:获取沙盒路径的类、处理网络数据的类、用户登录
系统提供的单例:
还有日历,等等
注意:单例不要滥用,因为单例的生命周期跟APP一样,也会占用内存。
潜规则系统一般定义,单例都是以
命名规则:shared+类名称
现在我们的目的是类无论创建多少次,都只分配一次存储空间,而分配存储空间的操作是在
在重写
为了让单例严谨一点,我们还要考虑copy这种情况,所以我们还要重写copy和mutableCopy。要重写copy和mutableCopy方法,必须先遵守协议。
在学习多线程之前,写单例的方法:BUT,在多线程下是错误的,因为线程不安全。
1.5.1两种方式创建单例
多线程之后,有两种方法创建单例。方式一:加线程锁
方式二:不需要做判断了,因为
1.5.1懒汉式单例(lazyinitialization)
在使用时才会创建。1.5.2饿汉式单例(eagerinitialization)
尽早的创建单例,可以利用拓展:
饿汉式在类创建的同时,已经创建好对象,以后不再改变,所以天生就是线程安全的
懒汉模式,如果需要线程安全还需要借助线程锁或者dispatch_once。无论是哪个方法,对性能都有降低,而实际99%的情况下都不需要同步。
2.NSOperation
是OC语言中基于GCD的面向对象的封装.使用起来比GCD更加简单(面向对象)
提供了一些用GCD不好实现的功能.
苹果推荐使用,使用NSOperation不用关心线程以及线程的生命周期.
NSOperation是个抽象类,无法直接使用.因为方法只有声明没有实现。
作为父类使用的.约束子类共有的属性和方法.
子类:
2.1.
2.2.
2.3.自定义NSOperation
操作默认是异步的.
队列:
队列默认是并发的.
核心:
4.1.GCD的核心:将任务添加到队列中
4.2.OP的核心:将operation添加到队列中
使用步骤:
先将需要执行的operation封装到一个NSOperation对象中.创建NSOperation对象.(其实是封装到NSOperation的子类中去。)
将NSOperation对象添加到NSOperationQueue中.
NSOperationQueue会自动将NSOperation取出来.
将取出的NSOperation封装的操作自动放到一条对应的新线程中执行.
2.1NSInvocationOpearion
核心:将使用
正确开启新线程的姿势
2.2NSBlockOperation
在实际开发时,如果要使用到
使用
2.3NSOperation和GCD的对比
名称 | GCD | NSOperation |
---|---|---|
核心概念 | 将任务添加到队列中 | 把操作添加到队列中 |
语言类型 | C | OC |
推出版本 | iOS4.0 | iOS2.0,在推出GCD之后又对底层进行了重写 |
封装地点 | 任务封装在block中 | 任务凤凰在Operation对象中 |
是否支持停止 | 可以,但是很麻烦 | 可以取消任务,但是正在执行的任务除外 |
优先级 | 只能设置队列的优先级 | 可以设置队列中每一个操作的优先级 |
依赖关系 | 建立任务间依赖关系比较复杂 | 可以跨腿咧设置操作的依赖关系 |
高级功能 | barrier\once\after\group | 最大操作并发数、继续/暂停/取消任务、跨队列设置操作的依赖关系 |
3.NSOperation的高级功能
最大操作并发数继续/暂停/取消全部
操作的优先级和监听操作执行完成的回调
操作间依赖关系
3.1队列的最大并发数
是队列的一个属性.限制同时执行的任务数.
比如,最大并发数设置成3,队列就会保证只同时执行3个任务.从而间接的控制了线程的数量.
线程可以复用.而且在线程回收的间隙可以及时的准备线程保证并发性.
注意:队列最大并发数不是线程数!!!
准备队列:也可以采用
3.2队列的暂停、继续、取消
YES代表暂停队列,NO代表恢复队列.
队列处于暂停状态时,是没有办法修改
3.2.1队列暂停
将队列挂起之后,队列中的操作就不会被调度,但是正在执行的操作不受影响正在执行的操作,没有办法暂停。
3.2.2队列继续
3.2.3队列取消
一旦调用正在执行的操作取消不了,如果要取消,需要自定义
队列取消全部操作时,会有一定的时间延迟
3.3操作间的依赖关系
不能循环建立操作间依赖关系.否则,队列不调度操作执行操作间可以跨队列建立依赖关系
要将操作间的依赖建立好了之后,再添加到队列中
先建立操作依赖关系
再把操作添加到队列
3.4.操作的优先级和监听操作执行完成的回调
4.列表异步加载网络图片
4.1SDWebImage加载网络图片
4.2NSOperation加载网络图片
注意:异步下载完图片之后,刷新UI一定要回到主线程5.GitHub初体验
6.AFN请求json数据
导入AFN框架和头文件#import“AFNetworking.h定义获取json文件的主方法
参数一:URL地址
参数二:不需要
参数三:下载进度
参数四:成功的block
参数五:失败的block
使用block字典转模型
数据加载之后,需要刷新页面
7.SDWebImage
相关文章推荐
- WinSock实现多线程网络文件传输程序(一)(MFC+WinSock附源代码)
- c#初学日记:多线程扫描网络计算机1
- 抢先式多线程网络蜘蛛
- 多线程网络编程
- Java Socket 编程——多线程网络聊天程序
- 多线程 循环 更新 网络状态
- 抢先式多线程网络蜘蛛
- 多线程测试网络情况,不同网段的机器用nbtstat判断是否开机
- 网络传输之同步异步SOCKET通讯和多线程
- C#初学者日记:多线程扫描网络计算机2
- delegate 与 多线程(摘自网络)
- J2ME中多线程网络连接编程的分析
- Linux多线程程序设计,(网络上流传的一道题)
- Windows Forms 实现安全的多线程详解(附带程序代码示例) (摘自网络)
- 对前一段时间学习网络和多线程编程的总结
- 多线程与网络服务的关系(转载)
- C#中的多线程(摘自网络)
- Java Socket 编程——多线程网络聊天程序
- 抢先式多线程网络蜘蛛
- 抢先式多线程网络爬虫spider在智能搜索引擎中的实现