级别: ★★☆☆☆
标签:「iOS」「GCD」「Objective-C」
做者: MrLiuQ
审校: QiShare团队php
前言:
这几篇文章是小编在钻研《Effective Objective-C 2.0》的知识产出,其中包含做者和小编的观点,以及小编整理的一些demo。但愿能帮助你们以简洁的文字快速领悟原做者的精华。
在这里,QiShare团队向原做者Matt Galloway表达诚挚的敬意。git
文章目录以下:
iOS 编写高质量Objective-C代码(一)
iOS 编写高质量Objective-C代码(二)
iOS 编写高质量Objective-C代码(三)
iOS 编写高质量Objective-C代码(四)
iOS 编写高质量Objective-C代码(五)
iOS 编写高质量Objective-C代码(六)
iOS 编写高质量Objective-C代码(七)
iOS 编写高质量Objective-C代码(八)github
本篇的主题是iOS中的 “ 大中枢开发 GCD ”。面试
先简单介绍一下今天的主角:GCD
。安全
Grand Central Dispatch
):一种与块相关的技术,提供了对线程的抽象管理(基于派发队列dispatch queue
)。GCD会根据系统资源状况,适时且高效地 “建立线程” 、“复用线程” 、 “销毁线程”。问:在iOS开发中,如何经过锁来提供同步机制?(之前面试中,常常问道的问题..)bash
答:在GCD出现以前,有两种方式:微信
@synchronized(self) {...}
- (void)synchronizedMethod {
@synchronized (self) {
// Safe area...
}
}
复制代码
[_lock lock];
& [_lock unlock];
_lock = [[NSLock alloc] init];
- (void)synchronizedMethod {
[_lock lock];
// Safe area..
[_lock unlock];
}
复制代码
不过这两种写法效率很低,若是有不少属性,那么每一个属性的同步块都要等其余同步块执行完毕才能执行。并发
GCD出现后,GCD与Block相结合,使开发变得更加简单、高效。async
问:如何保证属性读写时线程绝对安全? 答:在属性写入时,使用栅栏块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;
});
}
复制代码
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
并不必定是最佳选择。在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
是GCD
的一项特性,可以把任务进行分组管理,而后等待这组任务执行完毕时会有通知,开发者能够拿到结果真后继续下一步操做。 另外,经过dispatch group
在并发队列上同时执行多项任务的时候,GCD会根据系统资源状态来帮忙调度这些并发执行的任务。
例如:咱们开发中写一个单例,就可使用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
函数的行为经常与开发者所预期的不一样,此函数已经废弃,只应作调试之用。GCD
是按层级来组织的,因此没法单用某个队列对象来描述"当前队列"这一律念。dispatch_get_current_queue
函数用于解决由不能够重入的代码所引起的死锁,而后能用此函数解决的问题,一般也能够用"队列特定数据"来解决。最后,特别致谢:《Effective Objective-C 2.0》第六章。
关注咱们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)
推荐文章:
奇舞周刊
iOS 绘制渐变·基础篇
iOS 绘制渐变·实例篇