你研究过单例么?这样写单例效率最高.

首先,小汤我在这里,要表示一下歉意,本来是想要每天写一篇Swift的学习小tip的,无奈近期手头的money花差的差点儿相同了,仅仅能迫不得已,出门找工作去了,没能履行承诺之处还请大家见谅.

那么,废话不多说了,開始我们今天的主题: 单例 !

单例介绍:

说到单例,大家应该都不陌生,在传说中的那23种 (为啥我就会6种捏o(╯□╰)o…) 设计模式中,单例应该是属于和简单工厂模式并列的最简单的设计模式了,也应该是最经常使用的.

像这样简单易懂,又能有效提高程序执行效率的设计模式,作为一个iOS程序猿,必定是十分熟练的啦.

今天啊,小汤我就给大家介绍一下在Objective-C中,我们经常使用的单例模式的写法,以及小汤我在研究当中某种写法时,写出来的一个效率更高的写法.

当然啦,MRC下的写法,我就不多说了,已经有那么多大牛写过了,我就简化一下,直接写在ARC下的写法啦,MRC能够直接把相关代码套用过去即可喽~

网上流传的Objective-C的单例写法:

    + (instancetype)sharedPerson0{static id instance0 = nil;static BOOL once0 = YES;@synchronized(self){if (once0) {instance0 = [[Person alloc]init];once0 = NO;}}return instance0;}
以上就是网上流传已久的单例模式的写法啦.

通过GCD实现的单例模式写法:

    + (instancetype)sharedPerson1{static id instance1 = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance1 = [[self alloc]init];});return instance1;}
这是GCD方式,也就是使用dispatch_once实现的单例模式的写法.

首先展示一下两者是不是都实现了单例呢?为此,小汤我新建了一个Person类,在当中实现了这两种方法,然后在控制器启动的时候执行了以下两段代码

    for (int i = 0; i < 10; i++) {NSLog(@"--单例方法0:%@",[Person sharedPerson0]);}NSLog(@"-----");for (int i = 0; i < 10; i++) {NSLog(@"--单例方法1:%@",[Person sharedPerson1]);}NSLog(@"-----");

执行结果例如以下:

    2015-06-06 14:46:35.906 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.907 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.908 test[966:22855] --单例方法0:<Person: 0x7f9c19418740>2015-06-06 14:46:35.908 test[966:22855] -----2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.908 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.960 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.960 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.960 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.960 test[966:22855] --单例方法1:<Person: 0x7f9c1961e510>2015-06-06 14:46:35.960 test[966:22855] -----

能够看到这两种方式写的单例模式都是能够实现我们的需求的.
那么两者有什么差别呢?
以下我们来看一看两者在执行时间上的差别:

    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();for (int i = 0; i < 1000000; ++i) {[Person sharedPerson0];}NSLog(@"====方法0耗时:%f",CFAbsoluteTimeGetCurrent() - start);start = CFAbsoluteTimeGetCurrent();for (int i = 0; i < 1000000; ++i) {[Person sharedPerson1];}NSLog(@"====方法1耗时:%f",CFAbsoluteTimeGetCurrent() - start);

我通过上面这两个方法,比較两个单例模式在分别实例化100万个对象的耗时,结果例如以下:

    2015-06-06 14:50:47.899 test[1009:24267] ====方法0耗时:0.1842172015-06-06 14:50:47.981 test[1009:24267] ====方法1耗时:0.081377

能够看到,方法1的耗时明显要少于方法二的耗时,那么为什么GCD能够做到这一点呢?
小汤思考之后,认为应该是@synchronized这个锁对性能的消耗十分明显.

而在打印了dispatch_once这种方法的入參onceToken之后,发现,在实例化这个对象之前,onceToken的值为0,而之后变为-1.

于是,在这个基础上,小汤我想到了一个方法来降低这样的性能消耗.

那么问题来了?

dispatch_once会是通过小汤我想象的这样做的么?

小汤我的单例实现:

    + (instancetype)sharedPerson2{static id instance2 = nil;static BOOL once2 = YES;static BOOL isAlloc = NO;if (!isAlloc) {@synchronized(self){if (once2) {instance2 = [[Person alloc]init];once2 = NO;isAlloc = YES;}}}return instance2;}

我在进行同步锁之前,再进行了一次推断,这样会导致什么后果呢?


非常显然,因为内部有相互排斥锁,那么在实例化对象时,肯定仅仅有一个对象被实例化,然后在实例化对象之后,因为内部存在一个推断,那么就不会再有其它的对象被实例化,而在外面的这个推断,又能在下一次外部变量进行訪问的时候直接返回值,提高了效率.

说了那么多,先来測试一下小汤我的代码是不是能够创建一个单例呢?


測试代码:

    for (int i = 0; i < 10; i++) {NSLog(@"--单例方法2:%@",[Person sharedPerson2]);}NSLog(@"-----");

測试结果:

    2015-06-06 15:01:40.412 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.412 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.412 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.412 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.412 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] --单例方法2:<Person: 0x7fd891553e20>2015-06-06 15:01:40.413 test[1081:26913] -----

以上结果能够显示,小汤我的单例也是可行的.那么我们来对照一下我的这个实现和GCD的那种实现方式是不是一样呢?


效率測试代码:

    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();for (int i = 0; i < 1000000; ++i) {[Person sharedPerson1];}NSLog(@"====方法1耗时:%f",CFAbsoluteTimeGetCurrent() - start);start = CFAbsoluteTimeGetCurrent();for (int i = 0; i < 1000000; ++i) {[Person sharedPerson2];}NSLog(@"====方法2耗时:%f",CFAbsoluteTimeGetCurrent() - start);

还是比較100万次,我们来看看效率怎样呢?
測试结果:

    2015-06-06 15:04:58.696 test[1125:28301] ====方法1耗时:0.0897542015-06-06 15:04:58.763 test[1125:28301] ====方法2耗时:0.065470  

结果是不是非常惊讶?! 我 也 表 示 非常 吃 惊 !
没有想到小汤我写的单例的效率竟然比dispatch_once的效率还要略高那么一丝.
当然,这个仅仅是让小汤我稍微嘚瑟了一下,重点是,小汤我还是没想清楚,GCD下的这个dispatch_once究竟是怎么实现的呢?


是不是还存在优化的可能呢?希望对此有研究的各位大牛给个答案哈~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

office365在win7上使用订阅+win7在线升级win10就用它(亲测有效)

前言&#xff1a; 作为office365的重度使用用户&#xff0c;最近两天订阅到期&#xff0c;续订之后一直显示无法验证此订阅&#xff08;仅查看&#xff09;&#xff0c;office365未经授权&#xff0c;大多数功能已停用&#xff0c;狂晕&#xff01;&#xff01;&#xff01; 在…

HDU 4414 Finding crosses(搜索)

题目链接&#xff1a;HDU 4414 Finding crosses 【题目大意】 给你一张n*n的图&#xff0c;由o #这两个元素组成&#xff0c;让我们找其中有多少十字架。 十字架由#构成 十字架的纵向长度等于横向长度 &#xff0c; 且这个长度要为大于等于3的奇数。 构成十字架的#周围不能有多…

mongodb检查点_Mongodb 日志原理和操作

日志原理&#xff1a;WiredTiger使用检查点在磁盘上提供一致性数据视图&#xff0c;并允许MongoDB从上一个检查点恢复。 但是&#xff0c;如果MongoDB在检查点之间意外退出&#xff0c;则需要使用日志记录来恢复上次检查点之后发生的信息。通过日志记录&#xff0c;恢复过程如下…

UILabel 根据text的内容来调整大小

有时候&#xff0c;在UILabel的text过长的时候&#xff0c;我们需要让label进行自适应大小&#xff0c;之前我们必须要获得这个UILabel的size&#xff0c;这便是根据text的内容和性质&#xff08;字体&#xff0c;行间距等决定的&#xff09;。 在ios7中&#xff0c;使用boundi…

递归和分治思想及其应用

目录 递归和分治思想一些实例逆序输出字符串查找数组元祖是否存在汉诺塔问题八皇后问题更多&#xff1a;递归和分治思想 如果可以使用迭代&#xff0c;尽量别使用递归。由编译原理可以知道&#xff0c;每次自调用的时候&#xff0c;计算机都需要保存在调用&#xff0c;浪费时间…

AM+PM+FM基本调制原理及相关理论

总论&#xff1a; 调制信号&#xff1a; 模拟信号m(t)&#xff0c;可以是正弦波信号、方波信号等任意信号&#xff0c;又称基带信号 载波信号&#xff1a;一般为正弦波信号 已调信号&#xff1a; 幅度调制AM---A(t)随m(t)成比例变化----线性调制 相位调制PM---随m(t)成比…

unix网络编程 的环境配置

<unix网络编程> 的环境配置 首先在网上下载UNP的库文件&#xff0c;然后就可以安装学了。我的系统环境&#xff1a; 2.6.32-131.0.15.el6.i686 #1 SMP Sat Nov 12 17:30:50 CST 2011 i686 i686 i386 GNU/Linux LSB Version: :base-4.0-ia32:base-4.0-noarch:core-4.0-…

win32 api 文件操作!

CreateFile打开文件要对文件进行读写等操作&#xff0c;首先必须获得文件句柄&#xff0c;通过该函数可以获得文件句柄&#xff0c;该函数是通向文件世界的大门。ReadFile从文件中读取字节信息。在打开文件获得了文件句柄之后&#xff0c;则可以通过该函数读取数据。WriteFile向…

小说里的lt什么意思_游戏cpdd网络用语是什么意思 王者荣耀里很常见

[闽南网]随着互联网的发展&#xff0c;越来越多的流行语横空出世&#xff0c;在网络上得到广泛使用。当一个网络语流行的时候&#xff0c;不管在微博上还是贴吧里&#xff0c;都会看见和流行语有关的句子和表情包。眼下在各种游戏里&#xff0c;总是能看到游戏玩家们说“cpdd”…

POJ 1637 Sightseeing tour 混合图欧拉回路存在性判断

没有想到网络流还能解决这一类问题&#xff0c;完全想不到_ 一开始把所有的无向边制定任意方向有当做有向边看&#xff0c;然后统计每个点的入度和出度。以前有向图的欧拉回路判定是每个点的入读都等于出度&#xff0c;这样可以保证可以回到起点&#xff0c;现在在一些边可以调…

linux系统 硬链接和软链接

背景&#xff1a; 当几个用户同在一个项目里工作时。经常须要共享文件。假设一个共享文件同一时候出如今属于不同用户的不同文件夹下。工作起来就非常方便。比如B和C文件夹下有一文件D是两者都能够訪问和改动的共享文件&#xff0c;这样是非常方便&#xff0c;但也会有一些问题…

jquery纯数字验证

$(document).ready(function(){ //纯数字验证,只让输入数字,比如-号等都不然输入。 $(#user-defined).unbind(); $(#user-defined).bind(keyup change,function () { $(this).val($(this).val().replace(/\D/g,));}); });转载于:https://www.cnblogs.com/kuiyeit/p/47940…

闪电模型数学_最经典的数学模型

最经典的数学模型怎样得到最好的女孩子的数学模型【关键词】怎样得到最好女孩子数学模型由于老天爷在你的生命中安排的异性并不是同时出现任你挑选&#xff0c;因此无论你在何时选择结婚都是有机会成本的。人们常常希望能够获得一个最可爱的人作为自己的伴侣。但是&#xff0c;…

最近提交一个mysql5.7的bug,提醒自己以后注意写SQL要规范

最近帮朋友提交一个mysql5.7的bug , oracle mysql 的大神还回复我 , 以后注意书写sql规范 , 潜台词是不是不要给他们增加工作量 https://bugs.mysql.com/bug.php?id86610转载于:https://www.cnblogs.com/kelvin19840813/p/7052983.html

openssl 学习之从证书中提取RSA公钥N 和 E

原文链接: http://blog.csdn.net/kkxgx/article/details/19850509 通常数字证书包含很多信息&#xff0c;其中N和E值即我们称为的公钥。如何从PEM 或者DER格式的证书中提出证书呢&#xff1f;下面给出代码实现从PEM和DER编码的证书中提出N、E。 [cpp] view plaincopy #include …

获得汉字字符个数

//获得汉字字符个数function ChineseWordsCount(text:string):Integer;var i,sum,e,c,t: Integer;begin Result:0; c : 0; sum : Length(text); if Sum0 then exit; for i : 0 to sum do begin if Ord(text[i]) > 127 then begin Inc(c); end; end;…

2020湖南省技能竞赛获奖名单_2020年湖南省职业院校技能竞赛学院获奖情况通报...

由湖南省教育厅、湖南省人力资源和社会保障厅、湖南省农业农村厅等30个单位联合举办的2020年湖南省职业院校技能竞赛于2019年12月28日已经圆满结束所有竞赛项目&#xff0c;我院选派了190名选手参加了园林景观设计与施工、鸡新城疫抗体水平测定、集成电路开发及应用、农机维修、…

Web browser的发展演变

我们每天都在使用着浏览器&#xff0c;每个人使用的浏览器各不一样。在这个科技飞速发展的时代&#xff0c;一个游览器能否站住脚跟取决于使用者的数量&#xff0c;看用户是否喜欢这个产品&#xff0c;听取用户们的意见来改善。 我们这个年龄的人最初用到的浏览器肯定是IE浏览器…

nodejs简单层级结构配置文件

在NodeJS中使用配置文件&#xff0c;有几种比较不错的方案&#xff1a;第一种&#xff1a;文件格式使用json是毋容置疑的好方案。格式标准&#xff0c;易于理解&#xff0c;文件内容读取到内存之后&#xff0c;使用JSON的标准分析函数即可得到配置项。第二种&#xff1a;将配置…

C++语言基础(1)-命名空间

一个中大型软件往往由多名程序员共同开发&#xff0c;会使用大量的变量和函数&#xff0c;当有两个人都同时定义了一个名字相同的全局变量或函数的时候&#xff0c;若是把他们的代码整合在一块编译&#xff0c;此时编译器就会提示变量或函数重复定义&#xff0c;C为了解决这个问…