国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > iOS > 正文

使用設(shè)計(jì)模式中的Singleton單例模式來(lái)開發(fā)iOS應(yīng)用程序

2019-10-21 18:55:33
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
這篇文章主要介紹了使用設(shè)計(jì)模式中的Singleton單例模式來(lái)開發(fā)iOS應(yīng)用程序的例子,示例代碼為傳統(tǒng)的Objective-C語(yǔ)言,需要的朋友可以參考下
 

單例設(shè)計(jì)模式確切的說(shuō)就是一個(gè)類只有一個(gè)實(shí)例,有一個(gè)全局的接口來(lái)訪問(wèn)這個(gè)實(shí)例。當(dāng)?shù)谝淮屋d入的時(shí)候,它通常使用延時(shí)加載的方法創(chuàng)建單一實(shí)例。

提示:蘋果大量的使用了這種方法。例子:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager] 都返回一個(gè)單一對(duì)象。
你可能想知道你為什么要關(guān)心一個(gè)類有多個(gè)的實(shí)例。代碼和內(nèi)存都很便宜,不是嗎?

在一些情況下,一個(gè)類只有一個(gè)實(shí)例是有意義的。例如,這里沒(méi)有必要有多個(gè)登錄實(shí)例,除非你一次想寫入多個(gè)日志文件?;蛘撸粋€(gè)全局的配置類文件:它可以很容易的很安全的執(zhí)行一個(gè)公共資源,這樣的一個(gè)配置文件,要比同時(shí)修改多個(gè)配置類文件好很多。

如何使用單例模式

請(qǐng)看下面的圖片

設(shè)計(jì)模式,Singleton,iOS應(yīng)用程序

上面的圖片顯示的是一個(gè)登錄類,它有一個(gè)屬性(這個(gè)單一實(shí)例),有兩個(gè)方法:sharedInstance 和 init。

首先一個(gè)客戶端(client)發(fā)送 sharedInstance 信息,但是屬性 instance 還沒(méi)有初始化,所以你要先給這個(gè)類創(chuàng)建一個(gè)實(shí)例。

然后你調(diào)用 sharedInstance,instance 會(huì)馬上返回初始化的值。這個(gè)邏輯最終只會(huì)返回一個(gè)實(shí)例。

你需要執(zhí)行這個(gè)模式來(lái)創(chuàng)建單例類來(lái)管理所有的專輯數(shù)據(jù)。

你需要注意在項(xiàng)目里有一個(gè)叫 API 文件夾,給你的 APP 提供服務(wù)的所有類都需要放在這里。在這個(gè)文件夾里用 iOS/Cocoa Touch/Object-C class 創(chuàng)建一個(gè)新類。類的名字叫 LibraryAPI,子類選擇 NSObject。

打開 LibraryAPI.h 文件用下面的代碼替換里面的內(nèi)容:

復(fù)制代碼代碼如下:

@interface LibraryAPI: NSObject
+ (LibraryAPI*)sharedInstance;
@end

現(xiàn)在打開 LibraryAPI.m 文件,在 @implentation 后面添加如下方法:
復(fù)制代碼代碼如下:

+ (LibraryAPI*)sharedInstance 
{
    // 1
    static LibraryAPI *_sharedInstance = nil;

 

    // 2 
    static dispatch_once_t oncePredicate;

    // 3
    dispatch_once(&nocePredicate, ^{
        _sharedInstance = [[LibraryAPI alloc] init];
    });
    return _sharedInstance;
}


在這個(gè)短方法中做了這些事情:

 

在這個(gè)類中,聲明一個(gè)靜態(tài)變量來(lái)保存這個(gè)實(shí)例,保證它是一個(gè)全局可用的變量。
聲明一個(gè)靜態(tài)這是 dispatch_one_t,確保這些初始化代碼只能被執(zhí)行一次。
使用 Grand Central Dispatch(GCD)執(zhí)行一個(gè) block 來(lái)初始化 LibraryAPI 實(shí)例。這是單例設(shè)計(jì)模式的關(guān)鍵所在:一個(gè)類只能被實(shí)例化一次。
接下來(lái)執(zhí)行 sharedInstance,在 dispatch_once block 里的代碼是不會(huì)被執(zhí)行的(當(dāng)它已經(jīng)被執(zhí)行過(guò)一次后),它會(huì)返回之前創(chuàng)建的 LibraryAPI 實(shí)例。

提示:想了解更多關(guān)于 GCD 和使用它,請(qǐng)點(diǎn)擊這里的教程 Multithreading and Grand Central Dispatch,如何使用 Blocks 在這里。
你現(xiàn)在有一個(gè)單例對(duì)象來(lái)管理專輯了。下一步就是創(chuàng)建一個(gè)類用來(lái)保存你的專輯數(shù)據(jù)了。

用 iOS/Cocoa Touch/Object-C class 在 API 文件夾下創(chuàng)建一個(gè)新的類,名字叫 PersistencyManager,子類選擇 NSObject。

打開 PersistencyManager.h,在頂部引入面文件:

#import "Album.h"
然后在 @interface 后面加入下面代碼:

復(fù)制代碼代碼如下:

- (NSArray *)getAlbums;
- (void)addAlbums:(Album*)album atIndex:(int)index;
- (void)deleteAlbumAtIndex:(int)index;

上面的三個(gè)方法都需要跟專輯的數(shù)據(jù)相結(jié)合。

 

打開 PersistencyManager.m,在 @implementation 上面添加如下代碼:

復(fù)制代碼代碼如下:

@interface PersistencyManager () {
    NSMutableArray *albums;
}

上面的代碼是給類添加了一個(gè)擴(kuò)展,這是另一種給類添加私有方法和私有屬性的方法,類外面的成員是看不到這些的。這里,你聲明了一個(gè) NSMutableArray 來(lái)保存專輯的數(shù)據(jù)。這是一個(gè)可變數(shù)組,你可以很容易的添加和刪除專輯。

 

現(xiàn)在在 @implementation 下面添加實(shí)現(xiàn)代碼:

復(fù)制代碼代碼如下:

- (id)init {
    self = [super init];
    if (self) {
        albums = [NSMutableArray arrayWithArray:@[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"],
        [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"],
                [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"],
            [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"],
                [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];
    }
    return self;
}

在 init 里你在數(shù)組中加入了 5 張專輯。如果上面的專輯你不喜歡,你可以隨意替換成你喜歡的。:]

 

現(xiàn)存在 PersistencyManager.m 添加下面三個(gè)方法:

復(fù)制代碼代碼如下:

- (NSArray*)getAlbums
{
        return albums;
}

 

- (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 你的項(xiàng)目,確保所有的代碼都能正確編譯。


單例模式的使用場(chǎng)合

類只能有一個(gè)實(shí)例,并且必須從一個(gè)為人數(shù)值的訪問(wèn)點(diǎn)對(duì)其訪問(wèn)。
這個(gè)唯一的實(shí)例只能通過(guò)子類化進(jìn)行拓展,并且拓展的對(duì)象不會(huì)破壞客戶端代碼。

在Objective-C中方法都是公有的,而且OC的語(yǔ)言本身是動(dòng)態(tài)類型的,因此所有類都可以相互發(fā)送對(duì)方的消息。,并且Cocoa框架使用計(jì)數(shù)的內(nèi)存管理方式來(lái)維護(hù)對(duì)象的內(nèi)存中的生存期。
下面讓我們看一下OC當(dāng)中的單例模式的寫法,首先單例模式在ARC/MRC環(huán)境下的寫法有所不同,需要編寫2套不同的代碼

可以用宏判斷是否為ARC環(huán)境#if _has_feature(objc_arc)

復(fù)制代碼代碼如下:

#else
//MRC
#endif

單例模式- ARC -方法一

 

ARC中單例模式的實(shí)現(xiàn)
在 .m中保留一個(gè)全局的static的實(shí)例

復(fù)制代碼代碼如下:

 static id _instance;
 //重寫allocWithZone:方法,在這里創(chuàng)建唯一的實(shí)例(注意線程安全)
 + (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

提供1個(gè)類方法讓外界訪問(wèn)唯一的實(shí)例
復(fù)制代碼代碼如下:

    + (instancetype)sharedInstanceTool{
    @synchronized(self){
        if(_instance == nil){
            _instance = [[self alloc] init];
        }
    }
    return _instance;
}

 

實(shí)現(xiàn)copyWithZone:方法

復(fù)制代碼代碼如下:

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

我們?cè)趕haredInstanceTool,首先檢查類的唯一實(shí)例是否已經(jīng)創(chuàng)建,如果就會(huì)創(chuàng)建實(shí)例并將其返回。而之所以調(diào)用super而不是self,是因?yàn)橐呀?jīng)在self中重載了基本的對(duì)象分配的方法,需要借用父類的功能來(lái)幫助處理底層內(nèi)存的分配。
在allocWithZone:(struct _NSZone*)zone方法中,只是返回從sharedInstanceTool方法返回的類實(shí)例。而同樣的在Cocoa框架中調(diào)用allocWithZone:(struct _NSZone*)zone會(huì)分配內(nèi)存,引用計(jì)數(shù)會(huì)設(shè)置為1,然后返回實(shí)例。同樣的重寫(id)copyWithZone:(struct _NSZone *)zone方法,也是為了保證不會(huì)返回實(shí)例的副本,而是返回self.返回同一個(gè)實(shí)例。

 


方法二:

復(fù)制代碼代碼如下:

+(instancetype)sharedInstance {
    static WMSingleton *singleton = nil;
    if (! singleton) {
        singleton = [[self alloc] initPrivate];
    }
    return singleton;
}

 

- (instancetype)init {
    @throw [NSException exceptionWithName:@"這個(gè)是個(gè)單例"
                                   reason:@"應(yīng)該這樣調(diào)用 [WMSingleton sharedInstance]"
                                 userInfo:nil];
    return nil;
}
//實(shí)現(xiàn)自己真正的私有初始化方法
- (instancetype)initPrivate {
    self  = [super init];
    return self;
}


上面這段代碼中將singleton指針聲明為靜態(tài)變量。當(dāng)某個(gè)定義了靜態(tài)變量的方法返回時(shí),程序不會(huì)釋放相應(yīng)的變量。####singleton變量的初始值是nil,當(dāng)程序第一次執(zhí)行sharedInstance方法時(shí)會(huì)創(chuàng)建一個(gè)對(duì)象,并將新創(chuàng)建的對(duì)象的地址賦值給singleton變量。當(dāng)徐成再次執(zhí)行sharedInstance方法時(shí),無(wú)論多少次singleton變量仍然會(huì)指向最初那個(gè)創(chuàng)建的對(duì)象。因?yàn)橹赶驅(qū)ο蟮膕ingleton變量是強(qiáng)引用的,并且程序永遠(yuǎn)不會(huì)釋放該變量,所以singleton變量指向的對(duì)象也不會(huì)釋放。
線程安全。
上面的實(shí)例中我們通過(guò)@synchronized來(lái)添加了一個(gè)互斥鎖,以此來(lái)保證線程安全。而現(xiàn)在我們開始嘗試用線程的方式來(lái)實(shí)現(xiàn)一個(gè)加單的單例。

 

 

復(fù)制代碼代碼如下:

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

 

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

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


從上面的代碼我們可以看到,實(shí)現(xiàn)的思路基本上也是一致的我們?cè)趕haredInstanceTool,首先檢查類的唯一實(shí)例是否已經(jīng)創(chuàng)建,如果就會(huì)創(chuàng)建實(shí)例并將其返回。而略有不同的地方就是我們這次通過(guò)dispatch_once_t來(lái)保證線程的安全性。至于dispatch_once_t的用法這里就一一贅述了,線程的相關(guān)教程都會(huì)有其相關(guān)的描述。
到了這里一個(gè)簡(jiǎn)單的單例模式基本實(shí)現(xiàn)完成了,那么我們可以嘗試著把它封裝到一個(gè)宏里,然后方便其以后的調(diào)用
創(chuàng)建一個(gè)WMSingleton.h
復(fù)制代碼代碼如下:

// .h文件
#define WMSingletonH(name) + (instancetype)shared##name;

 

// .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; /
}


使用方法
復(fù)制代碼代碼如下:

//.h類
//引入這個(gè)宏文件
#import "WMSingleton.h"
@interface WMObject : NSObject
WMSingletonH(object)
@end
//.m類

 

@implementation WMObject
WMSingletonM(Car)
@end

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 分宜县| 新邵县| 海林市| 莆田市| 马公市| 鹤峰县| 平顺县| 淄博市| 铜鼓县| 平阳县| 临朐县| 呼图壁县| 舒兰市| 湘西| 六安市| 宁南县| 元朗区| 来宾市| 南投市| 赤水市| 丹巴县| 邹平县| 会昌县| 十堰市| 徐汇区| 金阳县| 洛扎县| 甘孜县| 衡东县| 甘洛县| 名山县| 镇原县| 马边| 东乌| 江西省| 应用必备| 望奎县| 威海市| 岚皋县| 合阳县| 桃江县|