单例模式

@synchronized

  1. 定义一个静态的全局的变量
    static Settings *sharedSettings = nil;

  2. 创建一个类方法,用来返回该类实例
    synchronized 这个主要是考虑多线程的程序,这个指令可以将{ } 内的代码限制在一个线程执行,如果某个线程没有执行完,其他的线程如果需要执行就得等着。

 + (Settings *)sharedInstance {
@synchronized(self){
if(sharedSettings  ==  nil){
            sharedSettings = [[self alloc] init];
          //做一些初始化操作
        }
    }
return  sharedSettings;
}
  1. 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
 + (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
        if (sharedSettings == nil) {
            sharedSettings = [super allocWithZone:zone];
        }
    }
    return sharedSettings;
}

dispatch_once
有些变量只需要初始化一次(如从文件中读取配置参数,读取设备型号等等),可以使用dispatch_once来进行读取优化,保证只调用API一次,以后就只要直接访问变量即可
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如
@synchronized之类的来防止使用多个线程或者队列时不同步的问题。

//范例如下:
static BOOL isTestMode;

+ (BOOL)isTestMode {

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
  NSNumber* obj = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFResourceTest"];
  isTestMode = [obj boolValue];
    });

  return isTestMode;
}

实际要如何使用这些呢?
好吧,假设有一个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];
该方法有很多优势
a. 线程安全
b. 很好满足静态分析器要求
c. 和自动引用计数(ARC)兼容
d. 仅需要少量代码

就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。

该方法有很多优势
a. 线程安全
b. 很好满足静态分析器要求
c. 和自动引用计数(ARC)兼容
d. 仅需要少量代码

该方法的劣势就是它仍然运行创建一个非共享的实例:我们通常在OC中实现一个单例方法都是这样:

static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });
    return instance;
}

可是这样就可以了么?我做了如下测试:

HLTestObject *objct1 = [HLTestObject sharedInstance];
NSLog(@"%@",objct1);
HLTestObject *objc2 = [[HLTestObject alloc] init];
NSLog(@"%@",objc2);
HLTestObject *objc3 = [HLTestObject new];
NSLog(@"%@",objc3);

看到这个测试,你想到打印结果了么?结果是这样的:

2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf39515510>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c4b70>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c4b70></hltestobject: 0x7fcf39515510>

很明显,通过三种方式创建出来的是不同的实例对象,这就违背了单例类有且仅有一个实例的定义。

为了防止别人不小心利用alloc/init方式创建示例,也为了防止别人故意为之,我们要保证不管用什么方式创建都只能是同一个实例对象,这就得重写另一个方法,实现如下:

static TYGAreaPickerView *sharedObject = nil;
+ (TYGPlaceholderHelper *)sharedInstance {

    static dispatch_once_t _singletonPredicate;
    dispatch_once(&_singletonPredicate, ^{
        sharedObject = [[super allocWithZone:nil] init];
    });
    return sharedObject;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [self sharedInstance];
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
        instance.height = 10;
        instance.object = [[NSObject alloc] init];
        instance.arrayM = [[NSMutableArray alloc] init];
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {
    return [[self alloc] init];
}
- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super init];
        instance.height = 10;
        instance.object = [[NSObject alloc] init];
        instance.arrayM = [[NSMutableArray alloc] init];
    });
    return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 单例模式 什么是单例模式? 单例模式想一个大独裁者,他规定在他的国度里面,所有数据的访问和请求都得经过他,甚至你要...
    GitHubPorter阅读 1,182评论 0 4
  • 线程间的通信 从子线程回到主线程 延时执行 iOS常见的延时执行有两种方式p 调用NSObject的方法 p 使用...
    一抹月光3053阅读 769评论 1 12
  • @WilliamAlex大叔 前言 目前流行的社交APP中都离不开单例的使用,我们来举个例子哈,比如现在流行的"糗...
    Alexander阅读 1,933评论 6 28
  • 一. ARC环境下的单例模式 单例模式的基本概念单例, 顾名思义, 即在整个程序中, 某一个类只有唯一一个实例, ...
    面糊阅读 763评论 0 50
  • 有些人一开口,你就知道这人厉害。曾经一度巨羡慕这样的人。 思路清晰,分工明确,直达重点..... 元认知,一种反思...
    Alexis_赵楠阅读 191评论 4 3