iOS 编写高质量Objective-C代码(七)—— GCD专栏
《编写高质量OC代码》已经顺利完成一二三四五六七篇!
附上链接:
iOS 编写高质量Objective-C代码(一)—— 简介
iOS 编写高质量Objective-C代码(二)—— 面向对象
iOS 编写高质量Objective-C代码(三)—— 接口和API设计
iOS 编写高质量Objective-C代码(四)—— 协议与分类
iOS 编写高质量Objective-C代码(五)—— 内存管理机制
iOS 编写高质量Objective-C代码(六)—— block专栏
iOS 编写高质量Objective-C代码(七)—— GCD专栏
本篇的主题是iOS中的 “ 大中枢开发 GCD ”。
先简单介绍一下今天的主角:GCD
。
- GCD(
Grand Central Dispatch
):一种与块相关的技术,提供了对线程的抽象管理(基于派发队列dispatch queue
)。GCD会根据系统资源情况,适时且高效地 “创建线程” 、“复用线程” 、 “销毁线程”。
一、多用派发队列,少用同步锁
问:在iOS开发中,如何通过锁来提供同步机制?(以前面试中,经常问道的问题..)
答:在GCD出现之前,有两种方式:
- 同步块:
@synchronized(self) {...}
- (void)synchronizedMethod { @synchronized (self) { // Safe area... } }
- NSLock:
[_lock lock];
&[_lock unlock];
_lock = [[NSLock alloc] init]; - (void)synchronizedMethod { [_lock lock]; // Safe area.. [_lock unlock]; }
不过这两种写法效率很低,如果有很多属性,那么每个属性的同步块都要等其他同步块执行完毕才能执行。
GCD出现后,GCD与Block相结合,使开发变得更加简单、高效。
问:如何保证属性读写时线程绝对安全?
答:在属性写入时,使用栅栏块barrier
。只有当前所有并发块都执行完毕后,才会执行barrier
块,然后才会继续向下处理。
- 思路如下:
- 代码如下:
_syncQueue = dispatch_queue_create("syncQueue", DISPATCH_QUEUE_CONCURRENT); //! 读取字符串 - (NSString *)someString { __block NSString *localSomeString; dispatch_sync(_syncQueue, ^{ localSomeString = _someString; }); return localSomeString; } - (void)setSomeString:(NSString *)someString { dispatch_barrier_async(_syncQueue, ^{ _someString = someString; }); }
二、多用GCD,少用performSelector系列方法
performSelector
系列方法的缺点有两个:
-
performSelector
系列方法可能引起内存泄漏:
在ARC环境下,编译器并不知道将要调用的选择子是什么,有没有返回值,返回值是什么,所以ARC不能判断返回值是否能释放,因此ARC做了一个比较谨慎的做法:只添加retain
,不添加release
。因此在有返回值或参数的时候可能导致内存泄漏。 -
performSelector
系列方法的返回值只能是void或OC对象类型。 -
performSelector
系列方法最多只能传入两个参数。
因此可以使用GCD来代替performSelector
系列方法:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //do something.. });
三、掌握GCD及操作队列的使用时机
GCD
性能很棒,但在执行后台任务时,GCD
并不一定是最佳选择。在iOS开发中,还有一种技术叫NSOperationQueue
。GCD
是基于C语言的API,性能较高。而NSOperationQueue
是基于GCD
的抽象。
使用NSOperation
和NSOperationQueue
的优点:
- 支持取消某个
NSOperation
:
在运行任务前,可以在NSOperation对象上调用cancel方法,用以表明此任务不需要执行。不过已经启动的任务无法取消。iOS 8之前,GCD队列是无法取消的,GCD是“安排好之后就不管了(fire and forget)”。iOS 8之后,支持dispatch_cancel
和dispatch_block_cancel
; -
NSOperation
支持多任务操作的依赖关系:
比如:任务A、B、C必须在任务D完成后执行。 - 支持通过
KVO
监控NSOperation
对象的属性:
例如:可以通过isCancelled
属性来判断任务是否已取消,通过isFinished
属性来判断任务是否已经完成等等; - 支持指定
NSOperationQueue
的优先级:
操作的优先级表示此操作与队列中其他操作之间的优先关系,优先级高的NSOperationQueue
先执行,优先级低的后执行。GCD的队列也有优先级,不过不是针对整个队列的; - 重用
NSOperation
对象:
在开发中你可以使用NSOperation
的子类或者自己创建NSOperation
对象来保存一些信息,可以在类中定义方法,使得代码能够多次使用;
四、通过Dispatch Group机制,根据系统资源状况来执行任务
dispatch group
是GCD
的一项特性,能够把任务进行分组管理,然后等待这组任务执行完毕时会有通知,开发者可以拿到结果然后继续下一步操作。
另外,通过dispatch group
在并发队列上同时执行多项任务的时候,GCD会根据系统资源状态来帮忙调度这些并发执行的任务。
五、使用dispatch_once来执行只需要运行一次的线程安全代码
例如:我们开发中写一个单例,就可以使用dispatch_once
:
+ (instancetype)sharedInstance { static Class *manager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[Class alloc] init]; }); return manager; }
六、不要使用dispatch_get_current_queue
理由如下:
-
dispatch_get_current_queue
函数的行为常常与开发者所预期的不同,此函数已经废弃,只应做调试之用。 - 由于
GCD
是按层级来组织的,所以无法单用某个队列对象来描述"当前队列"这一概念。 -
dispatch_get_current_queue
函数用于解决由不可以重入的代码所引发的死锁,然后能用此函数解决的问题,通常也可以用"队列特定数据"来解决。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Android中Message对象复用原理
Android 中 Message的应用 Message 在Android中主要是在 消息循环机制 中使用,即配合 Handler,Looper和MessageQueue来进行线程切换,线程间传递数据;以及配合Handler在IPC中传递数据; 这里不对这些进行展开,它不是我们关注的重点. 我们在代码中,被建议(网上或者前辈或看注释)用以下的方式来使用 Message,并且被告知,这样会提高性能. Message msg = Message.obtain(); /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain(); 嗯! 根据官方的文档,这样确实能够提高性能,将避免在大多数情况下创建新的对象! 下面我们来看它是如何实现高效的. Message对象复用的实现 Message能提高效率的原因是,将使用完的Message清除附带的数据后,添加到复用...
- 下一篇
Android爬坑之旅之WebView
不知不觉,Hybrid App已经成了目前比较主流的一种开发方式。 对于用户体验要求较高或者与硬件交互较多的功能我们一般都会采用Native原生的方式来实现。 而用户交互少,偏展示类,活动类的功能我们则通常采用H5的方式来实现, 例如新闻类的app,详情展示页一般就是H5的页面 ● 一方面图文排版上web有着先天的优势,同时纯展示类的页面在目前的移动设备上,性能体验已经很难让用户分辨是网页还是原生了; ● 另一方面,H5的页面跨平台,方便在原生客户端上实现分享功能,拥有较强的传播性,我们平时常见的活动页面也拥有这样的优势,所以你看到的活动页面也基本都是H5,只需轻轻一点就能分享到各个平台; ● 同时,H5的页面开发降低了开发成本,一套代码,web,android,ios都能访问。(然而实际开发过程中,H5的适配也都是各种泪) 既然Hybrid App有这么多优势,那在Android中我们通过什么样的方式在原生项目中嵌入H5页面呢? 那就不得不提到我们的WebVew了,作为官方唯一用来显示web的组件, 展示网页这样的任务也只能交给它了。 A View that displays web...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS8编译安装MySQL8.0.19
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G