Singleton 模式確保了不同的類別也使用相同的實例,並不會同時擁有 2 個或以上的實例,這種模式是非常常用的,例如 Java EE 的 Spring Framework 預設創造的 Spring Bean 也是使用 Singleton 模式的,但 Singleton 模式亦有一個壞處,就是應用程式使用了 Thread 時,同時有 2 個類別也更改 Singleton 的類別內容可能會出問題,你需要在 Objective-C 內使用 @synchronized 來令到程式不能同時更改某些內容,強迫一個執行完成完才到下一個,但使用這方法效率也會下降的。
下面的例子是保持資料庫的連接。
假如我有一個叫作 DBHelper 的類別:
DBHelper.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
@interface DBHelper : NSObject {
sqlite3 *database;
}
@property(retain, nonatomic) sqlite3 *database;
+ (DBHelper *)newInstance;
- (void)openDatabase;
- (void)closeDatabase;
@end
DBHelper.m
#import "DBHelper.h"
@implementation DBHelper
static DBHelper *instance = nil;
@synthesize database;
+ (DBHelper *)newInstance{
@synchronized(self) {
if (instance == nil){
instance = [[DBHelper alloc]init];
[instance openDatabase];
}
}
return instance;
}
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (instance == nil) {
instance = [super allocWithZone:zone];
return instance; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
- (void)openDatabase{
if (!database){
int result = sqlite3_open("ctlok.sqlite", &database);
if (result != SQLITE_OK){
NSLog(@"Open Database Failure");
}
}
}
- (void)closeDatabase{
if(database){
sqlite3_close(database);
}
}
@end
newInstance 的 Method 要使用 @synchronized 來防止 2 個不同類別同時製作 DBHelper 的實例。
使用方法:
DBHelper *dbHelper = [DBHelper newInstance];
sqlite3 *database = dbHelper.database;
以上程式碼即可以取得資料庫的連接。
整個應用程式關閉時使用以下程式碼關閉連接就可以了:
DBHelper *dbHelper = [DBHelper newInstance];
[dbHelper closeDatabase];
相關書籍: