你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 應用設計形式中的Singleton單例形式來開辟iOS運用法式

應用設計形式中的Singleton單例形式來開辟iOS運用法式

編輯:IOS開發綜合

單例設計形式確實的說就是一個類只要一個實例,有一個全局的接口來拜訪這個實例。當第一次載入的時刻,它平日應用延時加載的辦法創立單一實例。

提醒:蘋果年夜量的應用了這類辦法。例子:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager] 都前往一個單一對象。
你能夠想曉得你為何要關懷一個類有多個的實例。代碼和內存都很廉價,不是嗎?

在一些情形下,一個類只要一個實例是成心義的。例如,這裡沒有需要有多個登錄實例,除非你一次想寫入多個日記文件。或許,一個全局的設置裝備擺設類文件:它可以很輕易的很平安的履行一個公共資本,如許的一個設置裝備擺設文件,要比同時修正多個設置裝備擺設類文件好許多。

若何應用單例形式

請看上面的圖片

2016316181231772.png (233×152)

下面的圖片顯示的是一個登錄類,它有一個屬性(這個單一實例),有兩個辦法:sharedInstance 和 init。

起首一個客戶端(client)發送 sharedInstance 信息,然則屬性 instance 還沒有初始化,所以你要先給這個類創立一個實例。

然後你挪用 sharedInstance,instance 會立時前往初始化的值。這個邏輯終究只會前往一個實例。

你須要履行這個形式來創立單例類來治理一切的專輯數據。

你須要留意在項目裡有一個叫 API 文件夾,給你的 APP 供給辦事的一切類都須要放在這裡。在這個文件夾裡用 IOS\Cocoa Touch\Object-C class 創立一個新類。類的名字叫 LibraryAPI,子類選擇 NSObject。

翻開 LibraryAPI.h 文件用上面的代碼調換外面的內容:

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

如今翻開 LibraryAPI.m 文件,在 @implentation 前面添加以下辦法:

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

    // 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 前面參加上面代碼:

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

下面的三個辦法都須要跟專輯的數據相聯合。

翻開 PersistencyManager.m,在 @implementation 下面添加以下代碼:

@interface PersistencyManager () {
    NSMutableArray *albums;
}

下面的代碼是給類添加了一個擴大,這是另外一種給類添加公有辦法和公有屬性的辦法,類裡面的成員是看不到這些的。這裡,你聲清楚明了一個 NSMutableArray 來保留專輯的數據。這是一個可變數組,你可以很輕易的添加和刪除專輯。

如今在 @implementation 上面添加完成代碼:

- (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%20DosBat target=_blank class=infotextkey>Bathwater.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 裡你在數組中參加了 5 張專輯。假如下面的專輯你不愛好,你可以隨便調換成你愛好的。:]

現存在 PersistencyManager.m 添加上面三個辦法:

- (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 你的項目,確保一切的代碼都能准確編譯。


單例形式的應用場所

類只能有一個實例,而且必需從一個為人數值的拜訪點對其拜訪。
這個獨一的實例只能經由過程子類化停止拓展,而且拓展的對象不會損壞客戶端代碼。

在Objective-C中辦法都是私有的,並且OC的說話自己是靜態類型的,是以一切類都可以互相發送對方的新聞。,而且Cocoa框架應用計數的內存治理方法來保護對象的內存中的生計期。
上面讓我們看一下OC傍邊的單例形式的寫法,起首單例形式在ARC\MRC情況下的寫法有所分歧,須要編寫2套分歧的代碼

可以用宏斷定能否為ARC情況#if _has_feature(objc_arc)

#else
//MRC
#endif

單例形式- ARC -辦法一

ARC中單例形式的完成
在 .m中保存一個全局的static的實例

 static id _instance;
 //重寫allocWithZone:辦法,在這裡創立獨一的實例(留意線程平安)
 + (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

供給1個類辦法讓外界拜訪獨一的實例

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

完成copyWithZone:辦法

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

我們在sharedInstanceTool,起首檢討類的獨一實例能否曾經創立,假如就會創立實例並將其前往。而之所以挪用super而不是self,是由於曾經在self中重載了根本的對象分派的辦法,須要借用父類的功效來贊助處置底層內存的分派。
在allocWithZone:(struct _NSZone*)zone辦法中,只是前往從sharedInstanceTool辦法前往的類實例。而異樣的在Cocoa框架中挪用allocWithZone:(struct _NSZone*)zone會分派內存,援用計數會設置為1,然後前往實例。異樣的重寫(id)copyWithZone:(struct _NSZone *)zone辦法,也是為了包管不會前往實例的正本,而是前往self.前往統一個實例。


辦法二:

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

- (instancetype)init {
    @throw [NSException exceptionWithName:@"這個是個單例"
                                   reason:@"應當如許挪用 [WMSingleton sharedInstance]"
                                 userInfo:nil];
    return nil;
}
//完成本身真實的公有初始化辦法
- (instancetype)initPrivate {
    self  = [super init];
    return self;
}

下面這段代碼中將singleton指針聲明為靜態變量。當某個界說了靜態變量的辦法前往時,法式不會釋放響應的變量。####singleton變量的初始值是nil,當法式第一次履行sharedInstance辦法時會創立一個對象,並將新創立的對象的地址賦值給singleton變量。當徐成再次履行sharedInstance辦法時,不管若干次singleton變量依然會指向最後誰人創立的對象。由於指向對象的singleton變量是強援用的,而且法式永久不會釋放該變量,所以singleton變量指向的對象也不會釋放。
線程平安。
下面的實例中我們經由過程@synchronized來添加了一個互斥鎖,以此來包管線程平安。而如今我們開端測驗考試用線程的方法來完成一個加單的單例。


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

從下面的代碼我們可以看到,完成的思緒根本上也是分歧的我們在sharedInstanceTool,起首檢討類的獨一實例能否曾經創立,假如就會創立實例並將其前往。而略有分歧的處所就是我們此次經由過程dispatch_once_t來包管線程的平安性。至於dispatch_once_t的用法這裡就逐個贅述了,線程的相干教程都邑有其相干的描寫。
到了這裡一個簡略的單例形式根本完成完成了,那末我們可以測驗考試著把它封裝到一個宏裡,然前方便其今後的挪用
創立一個WMSingleton.h

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

應用辦法

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

@implementation WMObject
WMSingletonM(Car)
@end

【應用設計形式中的Singleton單例形式來開辟iOS運用法式】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved