Effective Objective-C(第41-46条)gcd大中枢派发、performSelector

    OC中多线程编程的核心就是block与gcd。这虽然是两种不同的技术,但他们是一并引入的。block是一种可在C、C++及OC代码中使用的“词法闭包”(lexical closure),它极为有用,借此机制,开发者可将代码像对象一样传递,令其在不同环境(context)下运行。在block的范围内,它可以访问到其中的全部变量。

    gcd是一种与block有关的技术,它提供了对线程的抽象,而这种抽象基于“派发队列”(dispatch queue)。开发者可将block排入队列中,有gcd负责处理所有调度事宜。gcd会根据系统资源情况,适时得创建、复用、摧毁后台线程,以便处理每个队列。此外,使用GCD还可以方便的完成常见编程任务,比如编写“只执行一次的线程安全代码”(thread-safe single-code execution),或者根据可用的系统资源来并发执行多个操作。

    block和gcd是当前OC的编程基石。因此必须理解其工作原理及功能

第41条:多用派发队列,少用同步锁

   在OC中,如果有多个线程要执行同一份代码,那么有时候可能会出问题。一般采用锁来实现某种同步机制。在GCD出现之前,第一种是采用“同步Block”,另一个办法是使用NSLock对象。这两种都会遇到死锁现象。使用gcd,它能以简单、高效的形式为代码枷锁。

    “串行同步队列”(serial synchronization queue)。将读取/写入都安排在同一个队列里,即可保证数据同步。

_syncQueue = dispatch_queue_create("com.effective-c.syncQueue",NULL);
-(NSString*) someString {
    __block NSString* localSomething;
    dispatch_sync(_syncQueue,^{
        localSomeString = _someString;
    });
    return localSomeString
}
-(void) setSomeString:(NSString*) someString{
    dispatch_sync(_syncQueue,^{
        _someString = someString;
    });
}

    此模式的思路是:把设置操作与获取操作都安排在序列化的队列里执行,这样的话,所有的针对属性的访问都是同步了。这点很想symbian的多动对象(OA)

    读、写操作。前者可以并发读取,但是后者不能并发。可以优化代码如下:

_syncQueue = dispatch_get_global_create("DISPATCH_QUEUE_PRIORITY_DEFAULT",NULL);
-(NSString*) someString {
    __block NSString* localSomething;
    dispatch_sync(_syncQueue,^{
        localSomeString = _someString;
    });
    return localSomeString
}
-(void) setSomeString:(NSString*) someString{
    dispatch_barrier_async(_syncQueue,^{
        _someString = someString;
    });
}

    其中dispatch_barrier_async是栅栏,在队列中,栅栏块必须单独执行,不能与其他块并行。如图所示:

Effective Objective-C(第41-46条)gcd大中枢派发、performSelector_第1张图片

第42条:多用gcd,少用performSelector系列方法

【本节要点】

● performSelector系列方法存在内存管理方面容易有疏忽。它无法确定将要执行的选择子具体是什么,因而ARC编译器也就无法插入适当的内存管理方法。

● performSelector系列方法能处理的选择子太过局限了,选择子的返回值类型及发送给方法的参数个数都有限制。

● 如果想把任务放到另一个线程上执行,那么最好不要用performSelector系列方法,而是使用gcd实现。

第43条:掌握gcd及操作队列的使用时机

    很少有其他技术能与gcd的同步机制相媲美。对于那些只需要执行一次的代码来说,也是如此,使用gcd的dispatch_once最为方便。然而在执行后台任务时候,gcd并不一定是最佳方式。还有一种技术叫做NSOpertationQueue,它虽然与gcd不同,但是却与之相关,开发者可以把操作以NSOpertation子类的形式放到队列中,这些操作也能够并发执行。

    在两者差别中,首先要注意:gcd是纯c的API,而操作队列是OC对象。gcd处理轻量级block而操作队列处理重量级OC对象。

    用NSOperationQueue类的addOperatonWithBlock方法搭配NSBlockOperation类来操作队列,其语法与纯gcd方法非常类似。使用NSOperation和NSOpertaionQueue的好处如下:

● 取消某个操作

● 指定操作间的依赖关系

● 通过键值观测机制监控NSOperation属性。

● 指定操作的优先级

● 重用NSOperation对象。

操作队列很多地方胜过派发队列。操作队列提供了很多执行任务的方法,而且都是写好了,直接就能用。开发者不用再编写复杂的调度器。

NSNotificationCenter使用了操作队列

本节要点

● 在解决多线程与任务管理问题时,派发队列并非唯一方案。

● 操作队列提供了一套高层次的OC API。能实现纯gcd所具备的绝大部分功能,而且还能完成一些更为复杂的操作,那些操作如果该用gcd来实现,则需要另外写代码。

第44条:通过dispatch group机制,根据系统资源状况来执行任务

(带补充)

第45条:使用dispatch_once来执行只需运行一次的线程安全代码

直接看代码吧,通常是单例的实现。

+(id) sharedInstance{
    static EOCClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{sharedInstance = [[self alloc]init];});
return sharedInstance;
}

第46条:不要使用dispatch_get_current_queue

-(NSString*) someString {
    __block NSString* localSomething;
    dispatch_sync(_syncQueue,^{
        localSomeString = _someString;
    });
    return localSomeString
}
-(void) setSomeString:(NSString*) someString{
    dispatch_sync(_syncQueue,^{
        _someString = someString;
    });
}

你可能感兴趣的:(Objective-C,Objective-C高效编程)