<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      設計模式之單例模式

      認真對待每時、每刻每一件事,把握當下、立即去做。

      單例模式,由于其簡單好用容易理解、同時在出問題時也容易定位的特點,在開發中經常用到的一個設計模式。

      一.什么是單例模式

      1. 單例模式的定義

      簡單的來說,一個單例類,在整個程序中只有一個實例,并且提供一個類方法供全局調用,在編譯時初始化這個類,然后一直保存在內存中,到程序(APP)退出時系統自動釋放這部分內存。

      2. 系統單例類了解

      UIApplication(應用程序實例類)

      NSNotificationCenter(消息中心類)

      NSFileManager(文件管理類)

      NSUserDefaults(應用程序設置)

      NSURLCache(請求緩存類)

      NSHTTPCookiesStorage(應用程序cookies池)

      3. 在那些地方會常用到單例類

      一般在應用程序中,經常需要調用的類,比如工具類,公共跳轉類等等,都建議使用單例模式。

      二.單例模式的生命周期

      1. 單例實例在存儲器中的位置

      程序中不同變量在手機存儲器中的存儲位置詳情見“內存管理”專題。

      在程序中,一個單例類在只能初始化一次,為了保證在使用時始終都是存在的,所以單例是在存儲器的全局區域。在編譯時分配內存,只要程序還在運行就會一直占用內存,在 APP 結束后由系統釋放這部分內存。

      2. 多次初始化單例類會發生什么?

      下面代碼我們在工程中初始化一次 UIApplication。最終運行的結果如下,程序直接崩潰,由此可以確定,一個單例類只能初始化一次。

      [[UIApplication alloc] init]; 
      Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'There can only be one UIApplication instance.'
      

      三.實現單例類

      1. 實現單例類的思路

      只能分配一次內存(初始化一次),因此要攔截 alloc 方法。alloc 方法的底層是 allocWithZone 方法。

      每個類只有一個對象,需要一個全局靜態變量來存儲這個對象。

      需要考慮線程安全。

      2. 單例的兩種模式

      懶漢模式:當使用這個單例對象的時候,才創建對象,就是 _instance 的懶加載形式。由于移動設備內存有限,所以這種方式最適合。

      餓漢模式:當類第一次加載的時候,就創建單例對象,并保存在 _instance 中。由于第一次加載就創建,內存從程序開始運行的時候就分配了,不適合移動設備。

      3. 單例基本形式(懶漢模式)

      @interface XBLoadTool : NSObject
      // 給外界快速創建單例對象使用
      + (instancetype)sharedLoadTool;
      @end
        
      #import "XBLoadTool.h"
      
      // 定義全局靜態變量,用來存儲創建好的單例對象,當外界需要時,返回
      static id _instance;
      
      @implementation XBLoadTool
      
      // 給外界快速創建單例對象使用
      + (instancetype)sharedLoadTool {
          if (_instance == nil) {
              // 避免出現多個線程同時創建_instance,加鎖
              @synchronized (self) {
                  // 使用懶加載,確保_instance只創建一次
                  if (_instance == nil) {
                      _instance = [[self alloc] init];
                  }
              }
          }
          return _instance;
      }
      
      // 重寫allocWithZone:方法---內存與sharedLoadTool方法體基本相同
      + (instancetype)allocWithZone:(NSZone *)zone {
          // 避免每次線程過來都加鎖,首先判斷一次,如果為空才會繼續加鎖并創建對象
          if(_instance == nil) {
              // 避免出現多個線程同時創建_instance,加鎖
              @synchronized(self) {
                  // 使用懶加載,確保_instance只創建一次
                  if(_instance == nil) {
                      //調用父類方法,分配空間
                      _instance = [super allocWithZone:zone];
                  }
              }
          }
          return _instance;
      }
      
      // 重寫copyWithZone:方法,避免實例對象的copy操作導致創建新的對象
      - (instancetype)copyWithZone:(NSZone *)zone {
          // 由于是對象方法,說明可能存在_instance對象,直接返回即可
          return _instance;
      }
      
      @end
      

      為什么全局變量要使用 static 修飾?

      static 修飾局部變量:

      • 其生命周期與全局變量相同,直到程序結束,只有一份內存空間。
      • 內存空間:僅有一份,多次調用函數時保留上次的值。
      • 作用域不變,僅限定義它的函數或代碼塊內,與未加static的局部變量作用域一致。

      static 修飾全局變量:

      • 內存空間:只有一份內存空間,全局變量本身只有一份,static 修飾后不改變此特性。
      • 全局變量可以在其他文件中,通過 extern id _instance 來聲明,然后直接在其他文件中調用。用 static 會將全局變量的鏈接屬性從 external 改為 internal,使其僅在當前文件可見,其他文件無法通過 extern 引用,任何方式都無法跨文件訪問。

      加鎖且懶加載的原理:懶加載是為了,確保整個類只有一個 instance。加鎖:多線程中,可能多個線程都發現當前的 _instance==nil,那么就會同時創建對象,不符合單例的原則,所以加鎖。但是加鎖容易引起效率降低,不能每次線程過來就加鎖,所以在加鎖之前首先判斷一次是否為空,不為空根本不需要創建,直接返回。為空則說明可能需要創建對象,那么再加鎖。

      3. GCD(dispatch_once_t)創建單例(懶漢模式)

      考慮到線程安全,蘋果官方推薦開發者使用 dispatch_once_t 來創建單例類。上面實例中,在 allocWithZone 方法和 sharedLoadTool 中,每次需要判斷是否為空,然后加鎖,其目的是為了保證 [[self alloc]init][super allocWithZone:zone] 代碼只執行一次,那么可以使用 GCD 的一次性代碼解決,另外,GCD 一次性代碼是線程安全的,所以不需要我們自己來處理加鎖問題。

      // 創建單例類方法,供全局調用 - retutn type instancetype
      + (instancetype)shareOnceClass {
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              _onceClass = [[XBOnceClass alloc] init];
          });
          return _onceClass;
      }
      
      // 修改 allocWithZone 方法
      + (instancetype)allocWithZone:(NSZone *)zone{
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              _onceClass = [super allocWithZone:zone
      ];
          });
          return _onceClass;
      }
      
      // 重寫 copyWithZone:方法,避免實例對象的 copy 操作導致創建新的對象
      -(instancetype)copyWithZone:(NSZone *)zone
      {
          //由于是對象方法,說明可能存在_onceClass對象,直接返回即可
          return _onceClass;
      }
      

      由于移動端特性,我們在開發過程中多用 GDG(懶漢模式)來創建單例。對于餓漢模式在第五大點有提到。

      四.單例模式的優缺點

      優點:

      1)在整個程序中只會實例化一次,所以在程序如果出了問題,可以快速的定位問題所在;

      2)由于在整個程序中只存在一個對象,節省了系統內存資源,提高了程序的運行效率;

      缺點:

      1)不能被繼承,不能有子類;

      2)不易被重寫或擴展(可以使用分類);

      3)同時,由于單例對象只要程序在運行中就會一直占用系統內存,該對象在閑置時并不能銷毀,在閑置時也消耗了系統內存資源;

      五.單例模式過程詳解

      1. 初始化過程解析

      重寫單例類的 alloc->allocWithZone 方法,確保這個單例類只被初始化一次。

      在 viewDidLoad 方法中調用單例類的 alloc 和 init 方法:[[XBOnceClass alloc] init];

      此時只是報黃點,但是并沒有報錯,Run 程序也可以成功,這樣的話,就不符合我們最開始使用單例模式的初衷來,這個類也可以隨便初始化類,為什么呢?因為我們并沒有獲取 OneTimeClass 類中的使用實例;

      因此可以重寫 alloc 方法的處理可以采用斷言或者系統為開發者提供的 NSException 類來告訴其他的同事這個類是單例類,不能多次初始化。

      // 斷言
      + (instancetype)alloc {
          NSCAssert(!_onceClass, @"單例XBOnceClass只能被初始化一次");
          return [super alloc];
      }
      
       //NSException
      + (instancetype)alloc {
         //如果已經初始化了
          if (_onceClass) {
            NSException *exception = [NSException exceptionWithName:@"提示" reason:@"XBOnceClass類只能初始化一次" userInfo:nil];
            [exception raise];
         }
        return [super alloc];
      }
      

      但是,如果我們的程序直接就崩潰了,這樣的做法與開發者開發 APP 的初衷是不是又相悖了,作為一個程序員的目的要給用戶一個交互友好的 APP,而不是一點小問題就崩潰。對于這種情況,可以用到 NSObect 類提供的 load 方法和 initialize 方法來控制,
      這兩個方法的調用時機,load 方法:當程序開始運行的時候,所有類都會加載到內存中(不管這個類有沒有使用),此時就會調用 load 方法,如果想某個操作在程序運行的過程中只執行一次,那么這個操作就可以放到 load 中,且在 main 函數調用之前調用,基于以上特點餓漢模式的單例創建就是放在 load 方法中; initialize 方法是當類第一次被使用的時候調用(比如調用類的方法),在 main 函數調用之后調用,如果子類沒有重寫該方法,那么父類的 initialize 方法可能會被執行多次,所以餓漢模式不能使用這種方法;

      這樣的話,餓漢模式下,如果我在單例類的 load 方法初始化這個類,是不是就保證了這個類在整個程序中調用一次呢?

      這樣就可以保證 sharedMusicTool 方法是最早調用的。同時,再次對 alloc 方法修改,無論在何時調用 instance 已經初始化了,如果再次調用 alloc 可直接返回_instance 實例。

      @interface XBMusicTool : NSObject
      
      //提供外界訪問的方法
      +(instancetype)sharedMusicTool;
      
      @end
      
      #import "XBMusicTool.h"
      
      // 定義靜態全局變量
      static id _instance;
      
      @implementation XBMusicTool
      
      // 實現方法
      + (instancetype)sharedMusicTool {
          return _instance;
      }
      
      // 重寫load方法
      + (void)load {
          // 不需要線程安全,類加載的時候線程還沒開始呢
          _instance = [[self alloc]init];
      }
      
      // 重寫allocWithZone方法
      + (instancetype)allocWithZone:(struct _NSZone *)zone {
          if(_instance == nil) {
              _instance = [super allocWithZone:zone];
          }
          return _instance;
      }
      
      // 重寫copyWithZone:方法,避免實例對象的copy操作導致創建新的對象
      -(instancetype)copyWithZone:(NSZone *)zone {
          // 由于是對象方法,說明可能存在_instance對象,直接返回即可
          return _instance;
      }
      
      @end
      

      最后在 ViewController 中打印調用 XBMusicTool 的 sharedMusicTool 和 alloc 方法,可以看到 Log 出來的內存地址是相同的,這就說明此時我的 XBMusicTool 類就只初始化了一次。

      2. 直接禁止方法的使用

      直接禁用方法,禁止調用這幾個方法,否則就報錯,編譯不過,不建議使用。

      -(instancetype) copy __attribute__((unavailable("OneTimeClass類只能初始化一次")));
      

      六.常見問題和學習

      1. 如果單例的靜態變量被置為 nil 了,是否內存會得到釋放?

      https://blog.csdn.net/jhcBoKe/article/details/108097693

      https://www.jianshu.com/p/5c0d002a0aad

      http://www.rzrgm.cn/dins/p/ios-singleton.html

      posted @ 2025-09-03 11:37  背包の技術  閱讀(27)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国偷自产一区二区三区在线视频| 亚洲国产亚洲国产路线久久 | 国产女人叫床高潮大片| 一本色道久久综合熟妇人妻| 亚洲精中文字幕二区三区| 亚洲尤码不卡av麻豆| 国产v综合v亚洲欧美大天堂| 国产成人亚洲欧美二区综合| 铜川市| 亚洲a片无码一区二区蜜桃| 精品视频不卡免费观看| 四虎永久在线精品免费播放| 亚洲精品久荜中文字幕| 亚洲av成人网人人蜜臀| 亚洲精品tv久久久久久久| 国产精品中文第一字幕| 色8久久人人97超碰香蕉987| 国产精品一区二区三区三级| 草草浮力影院| 国产成人久久综合第一区| 亚洲精品欧美综合二区| 色色97| 好吊视频在线一区二区三区| 老司机性色福利精品视频| 在线精品自拍亚洲第一区| 超碰成人人人做人人爽| 久久99精品久久久久久| 亚洲综合av男人的天堂| 国产乱子伦视频在线播放| 国内少妇人妻丰满av| 一区二区亚洲精品国产精| 午夜A理论片在线播放| 日韩一区在线中文字幕| 人妻夜夜爽天天爽三区麻豆av| 亚洲国产美女精品久久久| 亚洲区综合区小说区激情区| 国产亚洲一级特黄大片在线 | 久久爱在线视频在线观看 | awww在线天堂bd资源在线| 国产一级老熟女自拍视频| 国产午夜精品理论大片|