iOS設計模式之單例模式


1、什么是單例模式

  • 單例模式的定義
    某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。Ensures a class has only one instance, and provide a global point of access to it.保證一個類只有一個實例,並且提供一個全局的訪問入口訪問這個實例。
  • 單例類舉例
    • UIApplication(應用程序實例類)

    • NSNotificationCenter(消息中心類)

    • NSFileManager(文件管理類)

    • NSUserDefaults(應用程序設置)

    • NSURLCache(請求緩存類)

    • NSHTTPCookieStorage(應用程序cookies池)

  • 單例類使用時機?
    • 官方說法:
      一個類必須只有一個對象。客戶端必須通過一個眾所周知的入口訪問這個對象。
      這個唯一的對象需要擴展的時候,只能通過子類化的方式。客戶端的代碼能夠不需要任何修改就能夠使用擴展后的對象。

    • 舉例說明:在建模的時候,如果這個東西確實只需要一個對象,多余的對象都是無意義的,那么就考慮用單例模式。比如,存儲用戶信息的用戶管理類,在登錄成功后,其它各個業務模塊都可能用到。所以就會考慮用單例。

  • 單例模式有什么優缺點
    • 內存問題
      單例其實延長了對象的聲明周期,在整個程序的聲明周期中都是存在的,系統不能及時回收,就會一直占用內存。如果單例類所占用的內存大的化,問題可能更嚴重。又或者單例本身不是很大,但是他強引用了另外的比較大的對象的時候,那么那個比較大的對象就由於單例沒有被釋放,他也不會被釋放,這樣也造成了內存壓力。
      • 解決方法:
        針對這種單例本身不大,強引用對象比較大的情況,解決方式:比如一些可以重新加載的對象,需要的時候強引用,使用完成之后,不在強引用,釋放掉內存,下次使用的時候再加載回來。  
          
    • 循環依賴
      因為單例在創建之后,生命周期直到程序直到程序結束后才結束,當兩個單例類內的屬性創建都彼此依賴於對方時,就會造成死鎖。借用網上的例子
      在單例A中創建m屬性,這個屬性在單例A的init方法中進行初始化,初始化的時候m屬性依賴於另一個單例B創建。而單例B中創建了n屬性,這個屬性在單例B的init中進行初始化,初始化的時候n屬性依賴於前面的單例A創建。這樣創建出來會使用其中一個單例進行初始化的時候會出現死鎖問題。
      • 解決方法

        • 設計的時候就盡量不去產生這種互相依賴的關系。

        • 如果真的產生這種依賴關系就適當的打破死鎖鏈。

        • 實在要形成環或者無法控制,那么就異步初始化的方式,先過去,內容再填,內部需要做個標識,標識這個單例創建的是時候不能立即被使用或者不能完整被使用。  

2、單例類的生命周期

  • 不同的變量在手機存儲器中的存儲位置
位  置 存放的變量
臨時變量(由編譯器管理自動創建/分配/釋放的,棧中的內存被調用時處於存儲空間中,調用完畢后由系統系統自動釋放內存)
通過alloccallocmallocnew申請內存,由開發者手動在調用之后通過free或delete釋放內存。動態內存的生存期可以由我們決定,如果我們不釋放內存,程序將在最后才釋放掉動態內存,在ARC模式下,由系統自動管理。
全局區域 靜態變量(編譯時分配,APP結束時由系統釋放)
常量 常量(編譯時分配,APP結束時由系統釋放)
代碼區 存放代碼
  • 單例在手機存儲器中的位置
    單例對象一旦建立,對象指針保存在靜態區,單例對象在堆中分配的內存空間,只在應用程序終止后才會被釋放

    1. 單例模式創建的對象能夠一直存在於內存中不被釋放,並不只是由於持有一個自身的引用,本質是因為這個引用是靜態,也就是說,如果成員變量是非靜態的,它持有一個自身的引用,那么這個對象還是被回收。

    2. "系統內至少保持一個對象的引用",這個引用指的是從棧區或方法區中發出的引用,也就是安全的引用

    3. 類被實例化之后,是放在堆區中的,而我們是無法直接操作堆內存的,因此需要一個引用,指向堆區的某個區域,而這個引用,必須是從棧中(或方法區中)發出的,因為我們可以直接訪問棧內存,如果是從堆中發出的引用,是無意義的引用,我們根本訪問不到,因此會被回收。

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

  • 流程圖

3、新建一個單例類

  •  一般單例模式的創建方式(原則保存只創建一次);
    • .h
      @interface SingletonClass : NSObject
      + (instancetype)shareInstance;
      @end
    • .m

      + (instancetype)shareInstance {
          return [[super alloc]init];
      }
      
      /**
       * @see 使用alloc方法初始化一個類的實例的時候,默認是調用了allocWithZone的方法
       */
      + (instancetype)allocWithZone:(struct _NSZone *)zone {
          static SingletonClass *instance;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              instance = [super allocWithZone:zone];
          });
          return instance;
      }

 二,demo  

  單例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM