iOS开发笔记之三十四——多线程场景下的KVO使用参考方案
2016-04-15 16:41
435 查看
如果你取检索网络资料会发现,有人直接不建议把KVO与多线程混合使用,因为KVO的响应和KVO观察的值变化是在一个线程上的,不同的线程可能会导致不可预知的后果。参考资料见这里:
(1)http://objccn.io/issue-7-3/
(2)/article/1371338.html
当然,场景总是千变万化的,下面我就介绍一种多线程下使用KVO的场景。
具体场景如下:
(1)主线程里面请求数据,数据是一个类似http://www.dpfile.com/sc/appskin/20160309163700.zip的链接;
(2)数据拿到后,建立一个子线程,线程去请求zip包数据,并解压缩到本地(图片.png文件);
(3)通知(KVO)主线程,去本地目录取图片资源,刷新UI;
具体代码实现如下
1、方案一:
(1)主线程viewDidLoad方法中,注册监听,并发送数据请求;
(2)子线程中,解压缩并通知主线程刷新UI;
这样的调用KVO是直接跨越线程,实际运行时发现,最终从主线程发送请求,到图片刷出来,会经历5-10s的时间,zip包没有超过500k,并且wifi网络下,这个真的好慢,没有人能容忍。
KVO消息从子线程发出,到主线程上响应,而nonatomic属性的enablePromotionSkin是非线程安全的,这样设计会导致不可预知的问题。
2、方案二:
RAC本身有比较强大机制可以处理这种异步场景:
(1)主线程注册时,强制指定了主线程处理消息;
3、方案三:
如果不用RAC提供的机制,我们也可以采取直接主线程发消息的方法:
这种方法可以达到与方案二相同的效果。
(1)http://objccn.io/issue-7-3/
(2)/article/1371338.html
当然,场景总是千变万化的,下面我就介绍一种多线程下使用KVO的场景。
具体场景如下:
(1)主线程里面请求数据,数据是一个类似http://www.dpfile.com/sc/appskin/20160309163700.zip的链接;
(2)数据拿到后,建立一个子线程,线程去请求zip包数据,并解压缩到本地(图片.png文件);
(3)通知(KVO)主线程,去本地目录取图片资源,刷新UI;
具体代码实现如下
1、方案一:
(1)主线程viewDidLoad方法中,注册监听,并发送数据请求;
@weakify(self) [RACObserve(self, enablePromotionSkin)subscribeNext:^(NSNumber *enablePromotionSkin) { @strongify(self); if ([[self enablePromotionSkin] integerValue]) { //...刷新UI } }];
(2)子线程中,解压缩并通知主线程刷新UI;
- (RACSignal *)fetchSkinSignalWithConfig:(NVModelBaseOSAppPromoDo *)skinConfig { return (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ //下载、解压缩操作 //... //md5校验 if ([[responseData md5] isEqualToString:skinConfig.md5]) { self.enablePromotionSkin = @(YES); //通知主线程 } }); }]; }
这样的调用KVO是直接跨越线程,实际运行时发现,最终从主线程发送请求,到图片刷出来,会经历5-10s的时间,zip包没有超过500k,并且wifi网络下,这个真的好慢,没有人能容忍。
KVO消息从子线程发出,到主线程上响应,而nonatomic属性的enablePromotionSkin是非线程安全的,这样设计会导致不可预知的问题。
2、方案二:
RAC本身有比较强大机制可以处理这种异步场景:
(1)主线程注册时,强制指定了主线程处理消息;
@weakify(self) [[RACObserve(self, enablePromotionSkin) deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSNumber *enablePromotionSkin) { @strongify(self); if ([self enablePromotionSkin] integerValue) { //...刷新UI } }];(2)子线程处理时,强制由主线程处理;
- (RACSignal *)fetchSkinSignalWithConfig:(NVModelBaseOSAppPromoDo *)skinConfig { return [RACSignal startEagerlyWithScheduler:[RACScheduler mainThreadScheduler] block:^(id<RACSubscriber> subscriber) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ //.... }); }]; }这样之后,图片的下载一般会在2s左右就会刷新出来,基本达到了预期效果;
3、方案三:
如果不用RAC提供的机制,我们也可以采取直接主线程发消息的方法:
dispatch_async(dispatch_get_main_queue(), ^{ self.enablePromotionSkin = YES; });<span style="color:#0000ff;"> </span>
这种方法可以达到与方案二相同的效果。
相关文章推荐
- iOS 9.3 升级后无法真机测试 Could not find Developer Disk Image
- IOS读取项目中的plist
- iOS-核心动画(二)CABasicAnimation
- ios iOS手势识别的详细使用(拖动,缩放,旋转,点击,手势依赖,自定义手势)
- boost::iostreams——谁叫你把0x0a转成0x0d 0x0a的混蛋东西
- Ios8 Xcode6 设置Launch Image 启动图片
- Xcode:iOS崩溃日志分析方法
- iOS提交后申请加急审核
- iOS 富文本
- VFL 语句
- ios 生成一个动态的随机的头像/随机数的操作
- present和push
- iOS 中Base base64_encode编码
- iOS项目重构日记
- IOS 开发qq登陆界面
- iOS-动态计算Label的高度
- iOS 第三方新浪微博分享坑i
- 2016年最新苹果开发者账号注册申请流程最强详解!
- 多线程
- ios开发-- 开发细节(得到当前View的ViewController)