iOS 的单例模式 dispatch_once

iOS 的单例模式 dispatch_once


      有些变量仅仅须要初始化一次(如从文件里读取配置參数。读取设备型号等等),能够使用dispatch_once来进行读取优化。保证仅仅调用API一次,以后就仅仅要直接訪问变量就可以.

WeatherClient.h

#import "AFHTTPClient.h"

@interface WeatherClient : AFHTTPClient

+(WeatherClient *)sharedClient;

@end

WeatherClient.m

#import "WeatherClient.h"

@implementation WeatherClient

+(WeatherClient *)sharedClient
{
    static WeatherClient *sharedClient=nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{sharedClient =[[WeatherClient alloc] initWithBaseURL:[NSURL URLWithString:API]];
    });
    return sharedClient;
}


@end

在软件project中,单例是一种用于实现单例的数学概念,即将类的实例化限制成仅一个对象的设计模式。
或者我的理解是:
单例是一种类。该类仅仅能实例化一个对象。

    虽然这是单例的实际定义,但在Foundation框架中不一定是这样。比方NSFileMangerNSNotificationCenter。分别通过它们的类方法defaultManagerdefaultCenter获取。虽然不是严格意义的单例,这些类方法返回一个能够在应用的全部代码中訪问到的类的共享实例。在本文中我们也会採用该方法。
    使用Objective-C实现单例模式的最佳方式向来有非常多争论。开发人员(包含Apple在内)似乎每几年就会改变他们的想法。

当Apple引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他们也引入了一个非常适合用于实现单例模式的函数。

    该函数就是dispatch_once
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
    该函数接收一个dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型。实际上作为BOOL使用)。它还接收一个希望在应用的生命周期内仅被调度一次的代码块。对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被执行一次,并且还是线程安全的,这就意味着你不须要使用诸如@synchronized之类的来防止使用多个线程或者队列时不同步的问题。
    Apple的GCD Documentation证实了这一点:
假设被多个线程调用。该函数会同步等等直至代码块完毕。
    实际要怎样使用这些呢?
    好吧,如果有一个AccountManager类,你想在整个应用中訪问该类的共享实例。你能够按例如以下代码简单实现一个类方法:
+ (AccountManager *)sharedManager { 
    static AccountManager *sharedAccountManagerInstance = nil; 
 static dispatch_once_t predicate;
 dispatch_once(&predicate, ^{       
          sharedAccountManagerInstance = [[self alloc] init]; 
     });
    return sharedAccountManagerInstance; 
}
    这就意味着你不论什么时候訪问共享实例,须要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
    就这些,你如今在应用中就有一个共享的实例,该实例仅仅会被创建一次。
    该方法有非常多优势: 
           1 线程安全
           2 非常好满足静态分析器要求
           3 和自己主动引用计数(ARC)兼容 
           4 仅须要少量代码
    该方法的劣势就是它仍然执行创建一个非共享的实例:
AccountManager *accountManager = [[AccountManager alloc] init];
    有些时候你希望有这样的行为,但假设正在想要的是仅一个实例被实例化就须要注意这点。

 



posted @ 2017-07-09 14:21  mfmdaoyou  阅读(397)  评论(0编辑  收藏  举报