iOS中單例模式:MRC和ARC+GCD實現

來源:互聯網
上載者:User

標籤:c   style   class   blog   code   a   

  iOS中單例模式的實現一般分為兩種:MRC和ARC+GCD

  1.MRC(非ARC)

  非ARC的單例的實現方式:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <span style="font-family: 仿宋; font-size: 15px;">#import <Foundation/Foundation.h> @interface NoARCSingleton:NSObject <span>//這個屬性在後面調試有用處,而且也不要苦惱為什麼是retain?不應該是copy嗎?請繼續看下去,後面自然明白了<br></span>@property (nonatomic,retain) NSString *tempProperty; +(NoARCSingleton *)sharedInstance; @end @implementation NoARCSingleton static NoARCSingleton  *sharedInstance  = nil; //擷取一個單例對象 + (BVNonARCSingleton *)sharedInstance {<br>//--------------------------------------------------<br>  if (sharedInstance == nil) {         sharedInstance = [[super allocWithZone:NULL] init];     }    return sharedInstance;<br>//-------------------------------------------------- } //當第一次使用這個單例的時候,會調用這個init方法。 -(id)init {    self = [super init];   if(self){    //通常在這裡做一些相關的初始化任務   return self;     }      } //這個delloc方法永遠都不會被調用,因為在程式的生命週期內,該單例都必須存在,該方法可以不用實現 -(void)delloc {   [super dealloc]; }   //通過返回當前的單例對象的方式來防止執行個體化新的對象 + (id)allocWithZone:(NSZone*)zone {<br>  //線程相關的操作安全有</span>sharedInstance處理
?
1 2 3 4 5 6 7 <span style="font-family: 仿宋; font-size: 15px;">return [[self sharedInstance] retain]; } <br>//同樣的,不希望產生單例的多個拷貝,必須重寫 <br>- (id)copyWithZone:(NSZone *)zone { return self; } <br>//這個方法中什麼操作都不需要該單例並不需要一個引用計數(retain counter)<br> -(id)retain { return self; }<br> //替換掉引用計數器,這樣永遠都不會release這個單例了<br> - (NSUInteger)retainCount { return NSUIntegerMax; } <br>// 該方法是空的——不希望使用者release掉這個對象。<br> -(oneway void)release{ }<br> //除了返回單例外,什麼也不做。<br> -(id)autorelease { return self; } <br>@end <br>//@synchronized 的作用是建立一個互斥鎖,保證此時沒有其它線程對self對象進行修改。這個是objective-c的一個鎖定令牌,防止self對象在同一時間內被其它線程訪問,起到線程的保護作用。 一般在公用變數的時候使用,如單例模式或者操作類的static變數中使用。<br>//非ARC實現單例的方法是線程不安全的,如果有多個線程同時調用<span>sharedInstance方法擷取一個執行個體,而<span>sharedInstance需要花費1-2s的時間,那麼<span>NonARCSingleton的init方法可能會被多次的調用,也就是多個線程獲得的單例有可能不是一個單例,解決這個線程不安全的方式是使用<a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html" target="_blank"><span class="edui-filter-underline">@synchronized</span></a><span>來建立互斥鎖即可。<br>//<span>當然,該方法不能保證該單例中所有方法的調用都是安全執行緒的</span><br></span></span></span></span>//所以上面的橫線之間的代碼應該換成下面的代碼 @synchronized (self)</span> {      if(sharedInstance == nil)     {        sharedInstance = [[super allocWithZone:NULL] init]; }<br>#param mark <span style="font-family: 仿宋; font-size: 15px;">-提醒:在iOS中,一般不建議使用非ARC來實現單例模式。更好的方法是使用ARC+GCD來實現。</span>

  ARC實現的方式

?
1 2 3 4 5 6 7 <span style="font-family: 仿宋; font-size: 15px;">#import "ARCSingleton.h" @interface ARCSingleton : NSObject<br>//調試之用和上面的代碼作用類似的,這裡為什麼用weak呢?請繼續看下去~<br><span>@property  ( nonatomic, weak) NSString  *tempProperty;</span> + (ARCSingleton *)sharedInstance; @end @implementation ARCSingleton + (ARCSingleton *) sharedInstance {<br><span style="line-height: 1.5;">      static  ARCSingleton *sharedInstance = nil ;</span></span>
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <span style="font-family: 仿宋; font-size: 15px;">     static  dispatch_once_t onceToken = 0;  // 鎖      dispatch_once (&onceToken, ^ {     // 最多調用一次        sharedInstance = [[self  alloc] init];     });     return  sharedInstance; } //當第一次使用這個單例時,會調用這個init方法 -(id)init {     self = [super init];     if(self){        //初始化單例     }       return self;   } @end <br>//<span>在上面的代碼中,調用</span><span class="edui-filter-underline"><a href="http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html" target="_blank">Grand Central Dispatch <br>(GCD)</a></span><span>中的</span><span class="edui-filter-underline"><a href="https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once" target="_blank">dispatch_once</a></span><span>方法就可以確保ARCSingleton只被執行個體化一次。並且該方法是安全執行緒的,我們不用擔心在不同的線程中,會獲得不同的執行個體。(當然,該方法同樣不能保證該單例中所有方法的調用都是安全執行緒的)。</span><br> </span>

  當然在ARC中,不用GCD也是可以做到安全執行緒的,跟之前非ARC代碼中使用@synchronized一樣,如下代碼:

?
1 2 3 4 5 6 7 8 9 <span style="font-family: 仿宋; font-size: 15px;"> // 不使用GCD,通過@synchronized @synchronized (self) {    if(sharedInstance == nil)     {         sharedInstance = [[self alloc] init];     } } </span>

  為了簡化使用ARC+GCD來建立單例,可以使用下面這個宏

?
1 2 3 4 5 6 7 8 9 10 11 #define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) \   static dispatch_once_t onceToken = 0; \    static id sharedInstance = nil; \   dispatch_once(&onceToken, ^{ \   sharedInstance = block(); \}); \   return sharedInstance; \<br><span style="font-family: 仿宋; font-size: 15px;">//如果對於macro有問題的話強烈建議去腦補下貓神的文章http://onevcat.com/2014/01/black-magic-in-macro/<br>//另外貓神的很多文章都是很深入的建議有時間多去細細品味</span>

  宏寫完了之後那就so easy了!

  執行個體化方法實現:

?
1 2 3 4 5 6 + (BVARCSingleton *) sharedInstance {    DEFINE_SHARED_INSTANCE_USING_BLOCK(^{        return [[self alloc] init];     }); }<br>//Done

  單例的使用:單例的使用方法很簡單,在代碼中的任意位置,如下使用即可:

    在BVAppDelegate.m中添加標頭檔:
  #import "NonARCSingleton.h"
  #import "ARCSingleton.h"

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        [NonARCSingleton sharedInstance].tempProperty = @"非ARC單例的實現";         NSLog(@"%@", [BVNonARCSingleton sharedInstance].tempProperty);           [ARCSingleton sharedInstance].tempProperty = @"ARC單例的實現";         NSLog(@"%@", [ARCSingleton sharedInstance].tempProperty);          return YES; }

   附加乾貨

  __weak,__strong

  很少會見到 __weak 和 __strong 出現在聲明中,但我們需要對它們有一定的瞭解。 
預設情況下,一個指標都會使用 __strong 屬性,表明這是一個強引用。這意味著,只要引用存在,對象就不能被銷毀。這是一種所期望的行為:當所有(強)引用都去除時,對象才能被收集和釋放。不過, 有時我們卻希望禁用這種行為:一些集合類不應該增加其元素的引用,因為這會引起對象無法釋放。在這種情況下,我們需要使用弱引用(不用擔心,內建的集合類 就是這麼乾的),使用 __weak 關鍵字。NSHashTable 就是一個例子。當被引用的對象消失時,弱引用會自動化佈建為 nil。Cocoa 的 nsnotificationcenter 就是這麼一個例子,雖然這已經超出純 Objective-C 的語言範疇 .

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.