日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

iOS单例详解

發(fā)布時間:2025/7/14 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS单例详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在開發(fā)中經(jīng)常會用到單例設(shè)計模式,目的就是為了在程序的整個生命周期內(nèi),只會創(chuàng)建一個類的實例對象,而且只要程序不被殺死,該實例對象就不會被釋放。下面我們來看看單例的概念、用途、如何創(chuàng)建,以便加深理解。

作用

  • 在應(yīng)用這個模式時,單例對象的類必須保證只有一個實例存在。許多時候整個系統(tǒng)只需要擁有一個的全局對象,這樣有利于我們協(xié)調(diào)系統(tǒng)整體的行為。比如在APP開發(fā)中我們可能在任何地方都要使用用戶的信息,那么可以在登錄的時候就把用戶信息存放在一個文件里面,這些配置數(shù)據(jù)由一個單例對象統(tǒng)一讀取,然后服務(wù)進(jìn)程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在復(fù)雜環(huán)境下的配置管理。

  • 有的情況下,某個類可能只能有一個實例。比如說你寫了一個類用來播放音樂,那么不管任何時候只能有一個該類的實例來播放聲音。再比如,一臺計算機(jī)上可以連好幾個打印機(jī),但是這個計算機(jī)上的打印程序只能有一個,這里就可以通過單例模式來避免兩個打印任務(wù)同時輸出到打印機(jī)中,即在整個的打印過程中我只有一個打印程序的實例。

創(chuàng)建單例

有兩種方法來創(chuàng)建單例,下面分別介紹

1、GCD方式創(chuàng)建單例

static?id?_instance;???+?(instancetype)allocWithZone:(struct?_NSZone?*)zone?? {???static?dispatch_once_t?onceToken;???dispatch_once(&onceToken,?^{???_instance?=?[super?allocWithZone:zone];???});???return?_instance;??? }???+?(instancetype)sharedInstance?? {???static?dispatch_once_t?onceToken;???dispatch_once(&onceToken,?^{???_instance?=?[[self?alloc]?init];???});???return?_instance;??? }???-?(id)copyWithZone:(NSZone?*)zone??? {???return?_instance;??? }??-?(id)mutableCopyWithZone:(NSZone?*)zone?{???return?_instance;??? }

2、互斥鎖方式

static?id?_instance; +?(instancetype)allocWithZone:(struct?_NSZone?*)zone {????@synchronized(self)?{????????if?(_instance?==?nil)?{_instance?=?[super?allocWithZone:zone];}}????return?_instance; } +?(instancetype)sharedInstance {????@synchronized(self)?{????????if?(_instance?==?nil)?{_instance?=?[[self?alloc]?init];}}????return?_instance; } -?(id)copyWithZone:(NSZone?*)zone {????return?_instance; }

上面兩種方式都可以創(chuàng)建單例,而且保證了用戶不管是通過shareInstance方法,還是alloc、copy方法得到的實例都是一樣的。

上面代碼的關(guān)鍵之處就在于如何在多線程情況下保證創(chuàng)建的單例還是同一個。

我們先看看在GCD情況下,如果不使用dispatch_once和同步鎖創(chuàng)建單例會出現(xiàn)什么問題,去掉兩者后創(chuàng)建單例的代碼如下

+?(instancetype)sharedInstance?? {???if?(_instance?==?nil)?{_instance?=?[[self?alloc]?init];} }

假設(shè)此時有兩條線程:線程1和線程2,都在調(diào)用shareInstance方法來創(chuàng)建單例,那么線程1運行到if (_instance == nil)出發(fā)現(xiàn)_instance = nil,那么就會初始化一個_instance,假設(shè)此時線程2也運行到if的判斷處了,此時線程1還沒有創(chuàng)建完成實例_instance,所以此時_instance = nil還是成立的,那么線程2又會創(chuàng)建一個_instace。

此時就創(chuàng)建了兩個實例對象,導(dǎo)致問題。

解決辦法1、使用dispatch_once

dispatch_once保證程序在運行過程中只會被運行一次,那么假設(shè)此時線程1先執(zhí)行shareInstance方法,創(chuàng)建了一個實例對象,線程2就不會再去執(zhí)行dispatch_once的代碼了。從而保證了只會創(chuàng)建一個實例對象。

解決辦法2、使用互斥鎖

假設(shè)此時線程1在執(zhí)行shareInstance方法,那么synchronize大括號內(nèi)創(chuàng)建單例的代碼,如下所示:

if?(_instance?==?nil)?{_instance?=?[[self?alloc]?init];}

就會被當(dāng)做一個任務(wù)被加上了一把鎖。此時假設(shè)線程2也想執(zhí)行shareInstance方法創(chuàng)建單例,但是看到了線程1加的互斥鎖,就會進(jìn)入睡眠模式。等到線程1執(zhí)行完畢,才會被喚醒,然后去執(zhí)行上面所示的創(chuàng)建單例的代碼,但是此時_instance !=nil,所以不會再創(chuàng)建新的實例對象了。從而保證只會創(chuàng)建一個實例對象。

但是互斥鎖會影響性能,所以最好還是使用GCD方式創(chuàng)建單例。


宏創(chuàng)建單例

如果我們需要在程序中創(chuàng)建多個單例,那么需要在每個類中都寫上一次上述代碼,非常繁瑣。

我們可以使用宏來封裝單例的創(chuàng)建,這樣任何類需要創(chuàng)建單例,只需要一行代碼就搞定了。

實現(xiàn)代碼

Singleton.h文件 ==================================#define?SingletonH(name)?+?(instancetype)shared##name;#define?SingletonM(name)?\ static?id?_instance;?\\ +?(instancetype)allocWithZone:(struct?_NSZone?*)zone?\ {?\static?dispatch_once_t?onceToken;?\dispatch_once(&onceToken,?^{?\_instance?=?[super?allocWithZone:zone];?\});?\return?_instance;?\ }?\\ +?(instancetype)shared##name?\ {?\static?dispatch_once_t?onceToken;?\dispatch_once(&onceToken,?^{?\_instance?=?[[self?alloc]?init];?\});?\return?_instance;?\ }?\\ -?(id)copyWithZone:(NSZone?*)zone?\ {?\return?_instance;?\ }\ \ -?(id)mutableCopyWithZone:(NSZone?*)zone?{?\return?_instance;?\ }

如何調(diào)用

假設(shè)我們要在類viewcontroller中使用,調(diào)用方法如下:

viewcontroller.h文件 ===========================#import? #import?"Singleton.h"@interface?ViewController?:?UIViewController SingletonH(viewController) @endviewcontroller.m文件 ===========================@interface?ViewController?()@end@implementation?ViewControllerSingletonM(ViewController)-?(void)viewDidLoad?{[super?viewDidLoad];NSLog(@"%@?%@?%@?%@",?[ViewController?sharedViewController],[ViewController?sharedViewController],?[[ViewController?alloc]?init],[[ViewController?alloc]?init]);}@end

輸出結(jié)果

????

可以看到四個對象的內(nèi)存地址完全一樣,說明是同一個對象

轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/5908481.html

總結(jié)

以上是生活随笔為你收集整理的iOS单例详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。