什麼是單例?數組
一個類只容許有一個實例,在整個程序中須要屢次使用,共享同一份資源的時候,就能夠建立單例,通常封裝成工具類使用,蘋果封裝成單例經常使用的有 UIApplication
,NSUserDefaults
,NSNotificationCenter
,NSFIleManager
等等。工具
我之前的寫法 (不嚴謹的寫法)post
// Singleton.h @interface Singleton : NSObject + (instancetype)sharedInstance; @end // Singleton.m static Singleton *_instance = nil; @implementation Singleton +(instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[Singleton alloc] init]; }); return _instance; } @end
這不算真正意義上的單例,不能保證全局的惟一性,由於類方法和 [ [Class alloc] init ] 方法建立的單例內存地址可能不同,全部不嚴謹。spa
下面舉個栗子🌰code
Singleton *singOne = [Singleton sharedInstance]; Singleton *singTwo = [Singleton sharedInstance]; Singleton *singThere = [Singleton new]; Singleton *singFour = [[Singleton alloc] init]; NSLog(@"singOne:-> %@",singOne); NSLog(@"singTwo:-> %@",singTwo); NSLog(@"singThere:-> %@",singThere); NSLog(@"singFour:-> %@",singFour);
這時我看查看一下控制檯輸出的信息對象
2018-02-07 10:46:25.024988+0800 Markdown[2056:67507] singOne:-> <Singleton: 0x604000001a00> 2018-02-07 10:46:25.025222+0800 Markdown[2056:67507] singTwo:-> <Singleton: 0x604000001a00> 2018-02-07 10:46:25.025372+0800 Markdown[2056:67507] singThere:-> <Singleton: 0x6040000019a0> 2018-02-07 10:46:25.025646+0800 Markdown[2056:67507] singFour:-> <Singleton: 0x604000001a10>
結果很明顯, [Singleton sharedInstance]
類方法建立出來單例singOne
和 singTwo
的內純地址是同樣的,說明單例建立對了,可是看到new
和 alloc init
建立的singThere
和 singFour
的內存地址不同,同時也與singOne
和 singTwo
的地址不同.內存
百度一下還真有這類的帖子和博客,咱們主要的問題就是保證單例的惟一性,避免不當心用實例方法建立單例,全部應該保證alloc init
、new
、copy
方法建立的單例的的惟一性。資源
在建立對象的時候主要分這麼兩步 alloc (申請內存)init(初始化)開發
拷貝對象也是同樣的,覆寫copyWithZone方法,而後在方法中去調用類方法,返回單例對象。(在覆寫copyWithZone方法以前別忘記了簽署NSCopying協議)get
下面修改一下 Singleton.m
參考:iOS-單例模式簡單使用
// Singleton.m static Singleton *_instance = nil; @implementation Singleton +(instancetype)sharedInstance { if (_instance == nil) { _instance = [[super alloc]init]; } return _instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone{ return _instance; } - (id)mutableCopyWithZone:(NSZone *)zone{ return _instance; }
看一下控制檯輸出的結果:
2018-02-07 11:20:46.993693+0800 Markdown[2374:88765] singOne:-> <Singleton: 0x604000001990> 2018-02-07 11:20:46.993906+0800 Markdown[2374:88765] singTwo:-> <Singleton: 0x604000001990> 2018-02-07 11:20:46.994040+0800 Markdown[2374:88765] singThere:-> <Singleton: 0x604000001990> 2018-02-07 11:20:46.994146+0800 Markdown[2374:88765] singFour:-> <Singleton: 0x604000001990>
很明顯,改過 Singleton.m
後Singleton
類方法的類方法sharedInstance
和 實例方法 alloc init
的方法建立的單例內存地址同樣了,是否是有點小喜悅。
哪一個單例裏面沒有幾個屬性,最少也得有一個吧,要否則我要這鐵(dan)棒(li)有何用。
這就加幾個屬性試試。
Singleton *singOne = [Singleton sharedInstance]; SingOne.array = @[@"1",@"2",@"3"]; Singleton *singTwo = [Singleton sharedInstance]; SingOne.array = @[@"4",@"5",@"6"]; Singleton *singThere = [Singleton new]; SingThere.array = @[@"7",@"8",@"9"]; Singleton *singFour = [[Singleton alloc] init]; SingFour.array = @[@"0",@"0",@"0"]; NSLog(@" singOne:-> %@ , %p , %@ ",singOne,singOne.array,singOne.array); NSLog(@" singTwo:-> %@ , %p , %@ ",singTwo,singTwo.array,singTwo.array); NSLog(@"singThere:-> %@ , %p , %@ ",singThere,singThere.array,singThere.array); NSLog(@" singFour:-> %@ , %p , %@ ",singFour,singFour.array,singFour.array);
如今看看結果
array
屬性地址惟一,數組內容也惟一,知足標準。
2018-02-07 11:48:39.843225+0800 Markdown[2804:110175] singOne:-> <Singleton: 0x60000003ec60> , 0x600000445250 , ( 0, 0, 0 ) 2018-02-07 11:48:39.843439+0800 Markdown[2804:110175] singTwo:-> <Singleton: 0x60000003ec60> , 0x600000445250 , ( 0, 0, 0 ) 2018-02-07 11:48:39.843589+0800 Markdown[2804:110175] singThere:-> <Singleton: 0x60000003ec60> , 0x600000445250 , ( 0, 0, 0 ) 2018-02-07 11:48:39.843713+0800 Markdown[2804:110175] singFour:-> <Singleton: 0x60000003ec60> , 0x600000445250 , ( 0, 0, 0 )
感謝以上兩位博主的文章,借鑑作了一份單例的筆記,記錄開發中的問題並解決問題。