單例設計模式確切的說就是一個類只有一個實例,有一個全局的接口來訪問這個實例。當第一次載入的時候,它通常使用延時加載的方法創建單一實例。
提示:蘋果大量的使用了這種方法。例子:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager] 都返回一個單一對象。
你可能想知道你為什么要關心一個類有多個的實例。代碼和內存都很便宜,不是嗎?
在一些情況下,一個類只有一個實例是有意義的。例如,這里沒有必要有多個登錄實例,除非你一次想寫入多個日志文件。或者,一個全局的配置類文件:它可以很容易的很安全的執行一個公共資源,這樣的一個配置文件,要比同時修改多個配置類文件好很多。
如何使用單例模式
請看下面的圖片
上面的圖片顯示的是一個登錄類,它有一個屬性(這個單一實例),有兩個方法:sharedInstance 和 init。
首先一個客戶端(client)發送 sharedInstance 信息,但是屬性 instance 還沒有初始化,所以你要先給這個類創建一個實例。
然后你調用 sharedInstance,instance 會馬上返回初始化的值。這個邏輯最終只會返回一個實例。
你需要執行這個模式來創建單例類來管理所有的專輯數據。
你需要注意在項目里有一個叫 API 文件夾,給你的 APP 提供服務的所有類都需要放在這里。在這個文件夾里用 iOS/Cocoa Touch/Object-C class 創建一個新類。類的名字叫 LibraryAPI,子類選擇 NSObject。
打開 LibraryAPI.h 文件用下面的代碼替換里面的內容:
// 2
static dispatch_once_t oncePredicate;
// 3
dispatch_once(&nocePredicate, ^{
_sharedInstance = [[LibraryAPI alloc] init];
});
return _sharedInstance;
}
在這個類中,聲明一個靜態變量來保存這個實例,保證它是一個全局可用的變量。
聲明一個靜態這是 dispatch_one_t,確保這些初始化代碼只能被執行一次。
使用 Grand Central Dispatch(GCD)執行一個 block 來初始化 LibraryAPI 實例。這是單例設計模式的關鍵所在:一個類只能被實例化一次。
接下來執行 sharedInstance,在 dispatch_once block 里的代碼是不會被執行的(當它已經被執行過一次后),它會返回之前創建的 LibraryAPI 實例。
提示:想了解更多關于 GCD 和使用它,請點擊這里的教程 Multithreading and Grand Central Dispatch,如何使用 Blocks 在這里。
你現在有一個單例對象來管理專輯了。下一步就是創建一個類用來保存你的專輯數據了。
用 iOS/Cocoa Touch/Object-C class 在 API 文件夾下創建一個新的類,名字叫 PersistencyManager,子類選擇 NSObject。
打開 PersistencyManager.h,在頂部引入面文件:
#import "Album.h"
然后在 @interface 后面加入下面代碼:
打開 PersistencyManager.m,在 @implementation 上面添加如下代碼:
現在在 @implementation 下面添加實現代碼:
現存在 PersistencyManager.m 添加下面三個方法:
- (void)addAlbum:(Album*)album atIndex:(int)index
{
if (albums.count >= index)
[albums insertObject:album atIndex:index];
else
[albums addObject:album];
}
- (void)deleteAlbumAtIndex:(int)index
{
[albums removeObjectAtIndex:index];
}
Build 你的項目,確保所有的代碼都能正確編譯。
單例模式的使用場合
類只能有一個實例,并且必須從一個為人數值的訪問點對其訪問。
這個唯一的實例只能通過子類化進行拓展,并且拓展的對象不會破壞客戶端代碼。
在Objective-C中方法都是公有的,而且OC的語言本身是動態類型的,因此所有類都可以相互發送對方的消息。,并且Cocoa框架使用計數的內存管理方式來維護對象的內存中的生存期。
下面讓我們看一下OC當中的單例模式的寫法,首先單例模式在ARC/MRC環境下的寫法有所不同,需要編寫2套不同的代碼
可以用宏判斷是否為ARC環境#if _has_feature(objc_arc)
ARC中單例模式的實現
在 .m中保留一個全局的static的實例
實現copyWithZone:方法
方法二:
- (instancetype)init {
@throw [NSException exceptionWithName:@"這個是個單例"
reason:@"應該這樣調用 [WMSingleton sharedInstance]"
userInfo:nil];
return nil;
}
//實現自己真正的私有初始化方法
- (instancetype)initPrivate {
self = [super init];
return self;
}
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
}
// .m文件
#define WMSingletonM(name) /
static id _instance; /
/
+ (instancetype)allocWithZone:(struct _NSZone *)zone /
{ /
static dispatch_once_t onceToken; /
dispatch_once(&onceToken, ^{ /
_instance = [super allocWithZone:zone]; /
}); /
return _instance; /
} /
/
+ (instancetype)shared##name /
{ /
static dispatch_once_t onceToken; /
dispatch_once(&onceToken, ^{ /
_instance = [[self alloc] init]; /
}); /
return _instance; /
} /
/
- (id)copyWithZone:(NSZone *)zone /
{ /
return _instance; /
}
@implementation WMObject
WMSingletonM(Car)
@end
新聞熱點
疑難解答