【iOS】ARC-MRC下的單例及其應用

單例的應用十分廣泛,單例模式使一個類僅僅有一個實例安全

* 易於供外界訪問 .
* 方便控制實例個數 , 節約系統資源 .

* OC 中的 常見單例
如:UIApplication,    NSNotificationCenter,    NSUserDefaults,  NSFIleManager。

* 應用程序中用到的單例:
如:背景音樂。 音效管理等。


1、ARC中實現單例多線程

建立單例的步驟:
* 1 . 定義一個 全局的靜態變量 _instance ,用來記錄「第一次」被實例化出來的對象 .
* 2 . 重寫 allocWithZone 方法 ,此方法是爲對象分配內存空間必須會被調用的一個方法!
所以。在此方法中使用 dispatch_once ,能夠保證在 多線程 中, _instance 也僅僅能被「分配」一次空間 .
* 3 . 定義一個 sharedXXX「 類」方法 。方便其它使用單例的對象調用此單例 .
在此方法中,相同使用 dispatch_once ,保證使用類方法調用的對象,僅僅會被初始化一次。
凝視 :假設不考慮 copy& MRC ,以上三個步驟就能夠!
* 4 . 假設要支持 copy ,則需要 :
(1) 遵照 NSCopying 協議
(2) copyWithZone 方法中,直接返回 _instance


tips:性能

* 通常的寫法 ( 懶漢式 , 餓漢式 , 加鎖 ):
if(!_instance) _instance = [[XNShareTool alloc] init];
return _instance;
* 懶漢式是 線程不安全 . 所以實際中不這麼寫 還有餓漢式 , 加鎖等 .

* 但是 OC 中有其本身的寫法 . 需要 結合其對象生命周 期的一些方法來寫單例.

* 爲何要使用 dispatch_one ?

:spa

防止 多線程 同一時候進來 , 就至關與 Java 單例中的 加鎖機制 , 保證僅僅被實例化一次 .
但這裏使用的不是 synchronized,  是相似相互排斥鎖的東西 但比他的性能高 .

ARC中實現單例的代碼例如如下:
@implementation XNShareTool
/**
 步驟:
 1.一個靜態變量_inastance
 2.重寫allocWithZone, 在裏面用dispatch_once, 並調用super allocWithZone
 3.本身定義一個sharedXX, 用來獲取單例. 在裏面也調用dispatch_once, 實例化_instance
 -----------可選------------
 4.假設要支持copy. 則(先遵照NSCopying協議)重寫copyWithZone, 直接返回_instance就能夠.
 
 
 */
/**第1步: 存儲惟一實例*/
static XNShareTool *_instance;

/**第2步: 分配內存孔家時都會調用這種方法. 保證分配內存alloc時都一樣*/
+(id)allocWithZone:(struct _NSZone *)zone{
    //調用dispatch_once保證在多線程中也僅僅被實例化一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

/**第3步: 保證init初始化時都一樣*/
+(instancetype)sharedTool{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[XNShareTool alloc] init];
    });
    return _instance;
}

/**第4步: 保證copy時都一樣*/
-(id)copyWithZone:(NSZone *)zone{
    return _instance;
}

@end

測試代碼例如如下(打印單例對象的 地址都一樣):

-(void)viewDidLoad{
    //實例化一個類的幾種方法. 單例就是要保證明例化出來的類是同一個類
    //1.alloc init方法. 通常不這麼來調用單例.
    XNShareTool *t1 = [[XNShareTool alloc] init];
    XNShareTool *t2 = [[XNShareTool alloc] init];
    
    //2.類方法
    XNShareTool *t3 = [XNShareTool sharedTool];
    
    //3.copy
    XNShareTool *t4 = [t3 copy];
    
    NSLog(@"%@ %@ %@ %@", t1, t2, t3, t4);
}


2、MRC中運用單例


因爲 單例對象 是用 static 標記過的 , 所以存放在 靜態區 . 因此在 MRC 不需要 由程序猿 去管理 , 所以要去覆蓋一些 內存 管理的方法 .

實現部分與 ARC 一致 , 僅僅需要 覆蓋 一些 MRC 內存 管理 的方法:
* (id)retain .   單例中不需要添加引用計數器 . return self.
* - (id)autorelease .   僅僅有堆中的對象才需要 . 單例中不需要 .return self.
* - (NSUInteger)retainCount . ( 可寫可不寫 , 防止引發誤解 ). 單例中不需要改動引用計數。返回最大的無符號整數就能夠 .return UINT_MAX;
* - (oneway void)release . 不需要 release. 直接覆蓋 , 生命也不作 .
#import "XNShareTool.h"

@implementation XNShareTool

static XNShareTool *_instance;

+ (id)allocWithZone:(struct _NSZone *)zone {
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
	    _instance = [super allocWithZone:zone];
	});
	return _instance;
}

+ (instancetype)sharedTool {
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
	    _instance = [[XNShareTool alloc] init];
	});
	return _instance;
}

- (id)copyWithZone:(NSZone *)zone {
	return _instance;
}

#pragma mark - MRC中需要覆蓋的方法
//不需要計數器+1
- (id)retain {
	return self;
}

//不需要. 堆區的對象才需要
- (id)autorelease {
	return self;
}

//不需要
- (oneway void)release {
}

//不需要計數器個數. 直接返回最大無符號整數
- (NSUInteger)retainCount {
	return UINT_MAX;  //參照常量區字符串的retainCount
}

@end

3、ARC與MRC的整合

整合是爲了方便單例 既能在ARC中使用,又能在MRC中使用

而沒必要去改動單例中的方法。.net


詳細作法是使用宏定義:(推斷是不是ARC環境,是的話就省略內存管理的方法)

#if !__has_feature(objc_arc)線程

MRC中內存管理的方法放在這個地方code

#endif對象

代碼例如如下:blog

//=============================ARC/MRC整合=======================================
#pragma mark - MRC中需要覆蓋的方法, ARC與MRC的整合
#if !__has_feature(objc_arc)
- (id)retain {
	return self;
}

- (id)autorelease {
	return self;
}

- (oneway void)release {
}

- (NSUInteger)retainCount {
	return UINT_MAX;
}

#endif
//============================================================================


轉載請註明出處: http://blog.csdn.net/xn4545945
相關文章
相關標籤/搜索