objc单例的两种安全实现方案
所有转出博客园,请您注明出处:http://www.cnblogs.com/xiaobajiu/p/4122034.html
objc的单例的两种安全实现方案
首先应该知道单例的实现有两大类,一个是懒汉式,一个是饿汉式。所谓的懒汉式就是在我们用到某对象(资源)的时候,去问一个负责提供的方法要那个对象。那个方法发现没有这个资源时就去创建资源,如果是已经有该资源时就直接返回这个资源。而饿汉式就是那个负责提供的方法早已为我们准备好了我们想要的资源问它,它就提供给我们那个它早就准备好了的资源。
饿汉式的实现是简单而且好理解,但是它的理念不适合移动设备,因为饿汉式提前占用了内存,却不管我们需不需要。所以饿汉式的实现在最后作为一点补充。我们主要使用懒汉式,它符合移动的开发理念。
首先理清实现单例模式(懒汉式)的思路:
1.依靠什么来单例?
答:依靠静态变量,因为它在内存中只有一份。只要判断这个变量存不存在我们就知道需不需要创建一个对象赋值给那个静态变量。
2.但是在并发的情况下,我们同时去判断一个变量都得到了nil的结果,这两者就会都去创建一个新对象,那么会导致唯一性失效,就会使这两次访问得到不同的结果了,怎么解决?
答:加锁或者使用dispatch_once。
请先看加锁的方案。多说两句,加锁@synchronized()的效率可不是java,c#那么高的。《cocao开发者编程手册》47页这样写道:“这需要精确的垃圾回收,以及重写本地二进制文件的能力,Objectic-C编译器这两件事都做不了。所以,这个关键字非常低效”。但其实我们是可以避免频繁加锁,在网上找到的大多数代码都没有考虑到频繁加锁的问题的,而这里解决了这个问题,直接看代码吧:
//
// God.h
#import <Foundation/Foundation.h> @interface God : NSObject<NSCopying>
+ (God*)sharedGod; @end
//
// God.m #import "God.h"
static God *_singleGod; @implementation God
+ (id)allocWithZone:(struct _NSZone *)zone
{
if(!_singleGod){//防止频繁加锁
@synchronized([God class]){
if(!_singleGod)
_singleGod= [super allocWithZone:zone];
}
}
return _singleGod;
}
+ (God*)sharedGod
{
if(!_singleGod){//防止频繁加锁
@synchronized([God class]){
if(!_singleGod){
_singleGod= [[self alloc] init];
}
}
}
return _singleGod;
}
- (id)copyWithZone:(NSZone *)zone
{
return _singleGod;
}
//MRC下增加下面四个方法即可
- (id)retain
{
return self;
}
- (NSUInteger)retainCount
{
return ;
}
- (oneway void)release
{}
- (id)autorelease
{
return self;
}
@end
加锁的方案看起来似乎过于臃肿,使用GCD提供的dispatch_once来解决,将会使代码看起来简洁有力。(注:dispatch_once是GCD提供的一次性代码方案,该方法在整个程序的生命周期中只会执行一次。下一次执行到这里不会再执行了。)
dispatch_once版的实现如下:
//
// God2.m #import "God2.h"
static God2 *singleGod2;
@implementation God2
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleGod2= [super allocWithZone:zone];
});
return singleGod2;
}
+ (instancetype)sharedGod2
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleGod2= [[self alloc] init];
});
return singleGod2;
} - (id)copyWithZone:(NSZone *)zone
{
return singleGod2;
} //MRC下增加下面四个方法即可
- (id)retain
{
return self;
}
- (NSUInteger)retainCount
{
return ;
}
- (oneway void)release
{
}
- (id)autorelease
{
return self;
}
@end
使用dispatch_once来实现单例,我们更本不需要担心线程安全问题,因为GCD提供的解决方案本身就是线程安全的。大大简化了开发难度。
最后简单的补充一点关于懒汉式的写法,那么要知道+(void)load这个方法。它是类型加载到runtime时调用该方法,并且仅此一次。它的核心就是下面一行代码:
+ (void)load
{
singleGod3= [[self alloc] init];
}
欢迎各位朋友指正,以免误人子弟。
objc单例的两种安全实现方案的更多相关文章
- iOS单例的两种实现
单例模式算是开发中比较常见的一种模式了.在iOS中,单例有两种实现方式(至少我目前只发现两种).根据线程安全的实现来区分,一种是使用@synchronized,另一种是使用GCD的dispatch_o ...
- iOS 创建单例的两种方法
创建一个单例很多办法.我先列举一个苹果官方文档中的写法. [cpp] view plaincopy static AccountManager *DefaultManager = nil; + (Ac ...
- 【iOS开发】创建单例的两种方法
创建一个单例很多办法.我先列举一个苹果官方文档中的写法. [cpp] view plaincopy static AccountManager *DefaultManager = nil; + ( ...
- IOS创建单例的两种方法
1.0 苹果官方写法: static AccountManager *DefaultManager = nil; + (AccountManager *)defaultManager { if ( ...
- java单例的几种实现方法
java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...
- 属性传值,协议传值,block传值,单例传值四种界面传值方式
一.属性传值 对于属性传值而言,相对于其它的三种 方法来说,是最基础,最简单的一种 方法,但,属性传值 有很大的局限性,因为是适用于第一个界面向第二个界面传 值,第二个向第三个界面传值等等.N界面向N ...
- Objective-C和Swift实现单例的几种方式
在Swift开发中,我们对于跨类调用的变量常量,因为并没有OC中使用的全局头文件中写宏的形式,我们一般采用在类外定义全局变量/常量的形式来跨类调用.而问题在于目前写的项目需要在新添加的OC写的功能模块 ...
- 「Android」单例的五种写法
单例 发现博客园可以很好的设置自己的博客文章的展示,很开心,然后特此发一篇 其实这几种写法大家应该都会的,就权当拿来记录一下吧,以后复习巩固也比较方便. 这篇文章中的代码,来自一篇视频(我想找视频贴上 ...
- Java并发编程中的设计模式解析(二)一个单例的七种写法
Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...
随机推荐
- xshell连接虚拟机Connection failed
一.问题描述:xshell连接不了虚拟机,出现错误提示:Could not connect to '192.168.1.100' (port 22): Connection failed. 二.查找错 ...
- 引入 Tinker 之后如何在 Debug 模式下开启 Instant Run
在<Tinker + Bugly + Jenkins 爬坑之路>一文中讲了在接入 Tinker 之后,Jenkins 中的一些坑,由此,热修复算告一段落,但是,在直接 Run 模式运行时, ...
- Week1——JavaEE
本科目标 首先,对我来说自己想走的方向是JavaWeb后台开发,因此JavaEE对我来说也是比较重要的,想学好这门课.进一步巩固自己现有的基础知识,完善自己的项目经验,更加熟悉开发流程.在框架方面我还 ...
- 如何安装window7 语言包
很多下载的语言包都是.exe文件,双击后生成lp.cab文件. 这时马上把文件复制到另外一个文件夹中,直接拖最快. 这是 window7 sp1 的很多语言包下载地址(企业版和旗舰版通用):http: ...
- Python入门学习网址
Python入门学习网址:http://www.runoob.com/python/python-install.html
- 沉淀,再出发:PHP的简单使用
沉淀,再出发:PHP的简单使用 一.前言 关于PHP,笔者在本科的时候就听到了太多太多,可惜虽然看了很多的教材,听到了无数遍,也没有系统性的整理过和学习过这方面的知识,这点无论什么时候想起来都是一种遗 ...
- 主存储器与CPU的连接
半导体存储器的读写时间一般在十几至几百毫微秒之间,其芯片集成度高,体积小,片内含有译码器和寄存器等电路.常用的半导体存储器芯片有多字一位片和多字多位片,如16M位容量的芯片可以有16M×1位和4M×4 ...
- Java实现MD5加密及解密的代码实例分享
链接:http://www.jb51.net/article/86027.htm Java实现MD5加密及解密的代码实例分享 作者:厦门大学陈黎栋 字体:[增加 减小] 类型:转载 时间:2016-0 ...
- 深入剖析php执行原理(4):函数的调用
本章开始研究php中函数的调用和执行,先来看函数调用语句是如何被编译的. 我们前面的章节弄明白了函数体会被编译生成哪些zend_op指令,本章会研究函数调用语句会生成哪些zend_op指,等后面的章节 ...
- Spring Cloud(中文版)
原文链接:Spring Cloud I.云原生应用 Spring Cloud上下文:应用上下文服务 2.1.Bootstrap应用程序上下文 2.2.应用程序上下文层次结构 2.3.更改Bootstr ...