你研究過單例么?這樣寫單例效率最高.

首先,小湯我在這里,要表示一下歉意,本來是想要每天寫一篇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.pswp.cn/news/258373.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258373.shtml
英文地址,請注明出處:http://en.pswp.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為了解決這個問…