您的位置:首页 > 移动开发 > IOS开发

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方法中,注册监听,并发送数据请求;

@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>


这种方法可以达到与方案二相同的效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: