TheClass *newObject = [[TheClass alloc] init];
Do not overrideallocto include initialization code. Instead, implement class-specific versions ofinit...methods.
For historical reasons,allocinvokesallocWithZone:.
結論:alloc方法必須與init方法合用,來完成初始化過程。不要復寫alloc方法,可以復寫init方法來實現特別的需求。由於歷史原因,alloc會調用方法+allocWithZone: +allocWithZone: 使用方法:You must use aninit...method to complete the initialization process. For example:
Code Listing 3TheClass *newObject = [[TheClass allocWithZone:nil] init];
Do not overrideallocWithZone:to include any initialization code. Instead, class-specific versions ofinit...methods.
This method exists for historical reasons; memory zones are no longer used by Objective-C.
與alloc方法類似,此方法也需要與init方法合用。內存空間不再被oc使用,所以zone參數傳nil即可。 -init Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated. 由子類實現該方法,在得到內存分配之後立即初始化一個新的對象。 使用方法: Aninitmessage is coupled with analloc(orallocWithZone:) message in the same line of code: 與alloc或者allocWithZone組合使用。 如果要復寫,格式如下:- (instancetype)init { self = [super init]; if (self) { // Initialize self } return self; }-copy Returns the object returned bycopyWithZone:. 該方法的返回值是從copyWithZone:返回的 +copyWithZone: This method exists so class objects can be used in situations where you need an object that conforms to theNSCopyingprotocol. For example, this method lets you use a class object as a key to anNSDictionaryobject. You should not override this method. 只有准守了NSCopying協議的類對象,才能調用該方法。例如,使用該方法可以將類對象作為字典對象的key。不能override。 -mutableCopy Returns the object returned bymutableCopyWithZone:where the zone isnil. 與 -copy 同理 +mutableCopyWithZone: This method exists so class objects can be used in situations where you need an object that conforms to theNSMutableCopyingprotocol. For example, this method lets you use a class object as a key to anNSDictionaryobject. You should not override this method. 與 -copyWithZone:同理。 +new This method is a combination ofallocandinit. Likealloc, it initializes theisainstance variable of the new object so it points to the class data structure. It then invokes theinitmethod to complete the initialization process. 該方法是alloc和init兩個方法的結合版。和alloc方法類似,它初始化新對象的isa指針(指向類數據結構)實例變量。然後自動調用init方法來完成該實例化過程。 綜上所述 單例的初始化只要保證,- alloc -init 、-new、-copy、mutableCopy、以上四個方法創建出來的對象是同一個就ok了。 Demo 代碼如下
#import@interface SingleInstance : NSObject + (instancetype)shareInstance; @property (nonatomic ,assign) NSInteger factor1; //測試用 @end
#import "SingleInstance.h" @implementation SingleInstance static SingleInstance *instance = nil; + (instancetype)shareInstance { static SingleInstance *instance; static dispatch_once_t onceToken; //dispatch_once (If called simultaneously from multiple threads, this function waits synchronously until the block has completed. 由官方解釋,該函數是線程安全的) dispatch_once(&onceToken, ^{ instance = [[super allocWithZone:NULL] init]; }); return instance; } //保證從-alloc-init和-new方法返回的對象是由shareInstance返回的 + (instancetype)allocWithZone:(struct _NSZone *)zone { return [SingleInstance shareInstance]; } //保證從copy獲取的對象是由shareInstance返回的 - (id)copyWithZone:(struct _NSZone *)zone { return [SingleInstance shareInstance]; } //保證從mutableCopy獲取的對象是由shareInstance返回的 - (id)mutableCopyWithZone:(struct _NSZone *)zone { return [SingleInstance shareInstance]; } @end以上:保證了無論用何種方式獲取單例對象,獲取到的都是同一個對象。 驗證代碼如下
SingleInstance *single1 = [[SingleInstance alloc] init]; SingleInstance *single2 = [SingleInstance new]; SingleInstance *single3 = [SingleInstance shareInstance]; SingleInstance *single4 = [single1 copy];//調用此方法獲取對象,需要該類重寫過copyWithZone:方法,不然會crash SingleInstance *single5 = [single1 mutableCopy];//需重寫mutableCopyWithZone:,否則crash single1.factor1 = 1; single2.factor1 = 2; single3.factor1 = 3; single4.factor1 = 4; single5.factor1 = 5; NSLog(@"s1 value = %ld \n",single1.factor1); NSLog(@"s2 value = %ld \n",single2.factor1); NSLog(@"s3 value = %ld \n",single3.factor1); NSLog(@"s4 value = %ld \n",single4.factor1); NSLog(@"s5 value = %ld \n",single5.factor1); NSLog(@"memory address \n %@ \n %@ \n %@ \n %@ \n %@",single1,single2,single3,single4,single5);控制台打印結果為: ttt[44738:1478271] s1 value = 5
//開始模擬 - (void)simulateStart { SingleInstance *single1 = [[SingleInstance alloc] init]; single1.factor1 = 10;//總共有10張票 [self performSelectorInBackground:@selector(sellTickets) withObject:nil]; [self performSelectorInBackground:@selector(sellTickets) withObject:nil]; [self performSelectorInBackground:@selector(sellTickets) withObject:nil]; }
- (void)sellTickets { SingleInstance *single1 = [SingleInstance shareInstance]; NSThread *thread = [NSThread currentThread]; thread.name = [NSString stringWithFormat:@"%.6f",[[NSDate date] timeIntervalSince1970]]; dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ //檢查票數 for (int i = 0; i<10; i++) { NSInteger leftTicketsCount = single1.factor1; if (leftTicketsCount <= 0) { NSLog(@"賣光了 \n"); break; } else { [NSThread sleepForTimeInterval:0.02]; NSInteger remain = single1.factor1; single1.factor1--; NSInteger left = single1.factor1; NSLog(@"線程名:%@ 余票數 %ld , 賣出一張 , 剩余票數 %ld \n",thread.name,remain,left); } } }); }控制台打印的結果為: 線程名:1484826739.634151余票數 9 ,賣出一張 ,剩余票數 8
- (void)sellTickets { SingleInstance *single1 = [SingleInstance shareInstance]; NSThread *thread = [NSThread currentThread]; thread.name = [NSString stringWithFormat:@"%.6f",[[NSDate date] timeIntervalSince1970]]; dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ //注意一定要把線程對數據操作的代碼放在同步鎖的花括號裡面 @synchronized (single1) { //檢查票數 for (int i = 0; i<11; i++) { NSInteger leftTicketsCount = single1.factor1; if (leftTicketsCount <= 0) { NSLog(@"賣光了 \n"); break; } else { [NSThread sleepForTimeInterval:0.02]; NSInteger remain = single1.factor1; single1.factor1--; NSInteger left = single1.factor1; NSLog(@"線程名:%@ 余票數 %ld , 賣出一張 , 剩余票數 %ld \n",thread.name,remain,left); } } } }); }控制台打印數據為: 線程名:1484827607.308329余票數 10 ,賣出一張 ,剩余票數 9