亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

使用設計模式中的Singleton單例模式來開發iOS應用程序

2020-07-26 03:25:47
字體:
來源:轉載
供稿:網友

單例設計模式確切的說就是一個類只有一個實例,有一個全局的接口來訪問這個實例。當第一次載入的時候,它通常使用延時加載的方法創建單一實例。

提示:蘋果大量的使用了這種方法。例子:[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%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 里你在數組中加入了 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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91av福利视频| 欧美成人精品影院| 国产九九精品视频| 黑人狂躁日本妞一区二区三区| 成人精品久久av网站| 成人福利免费观看| 91成人天堂久久成人| 2019精品视频| 成人h片在线播放免费网站| 久久人91精品久久久久久不卡| 久久亚洲国产精品成人av秋霞| 亚洲欧洲成视频免费观看| 97精品视频在线观看| 色香阁99久久精品久久久| 亚洲另类激情图| 8050国产精品久久久久久| 5566成人精品视频免费| 国产剧情日韩欧美| 色小说视频一区| 中文字幕日韩欧美精品在线观看| 欧美日韩另类字幕中文| 国产福利视频一区| 3344国产精品免费看| 国产91热爆ts人妖在线| 中文字幕日韩av电影| 18性欧美xxxⅹ性满足| 国产精品久久久久高潮| 日韩免费高清在线观看| 亚洲美女激情视频| 亚洲欧美日韩天堂一区二区| 欧美一级高清免费播放| 久久精品国产电影| 亚洲性视频网站| 国产suv精品一区二区| 久久夜精品香蕉| 成人免费在线视频网址| 亚洲国产欧美日韩精品| 精品久久国产精品| 亚洲国产日韩欧美在线动漫| 欧美成人全部免费| 一区二区三区视频观看| 久久黄色av网站| 秋霞成人午夜鲁丝一区二区三区| 亚洲精品一区二区在线| 亚洲大胆人体在线| 国产狼人综合免费视频| 国产亚洲欧美日韩精品| 97视频色精品| 国产性猛交xxxx免费看久久| 九色精品美女在线| 日本高清不卡在线| 成人免费视频a| 91禁国产网站| 欧美美女15p| 亚洲欧洲一区二区三区久久| 亚洲精品少妇网址| 欧美福利视频在线观看| 国产精品扒开腿做爽爽爽男男| 中文字幕久热精品在线视频| 亚洲aⅴ日韩av电影在线观看| 在线视频国产日韩| 国产精品美女无圣光视频| 久久视频在线观看免费| 国产欧美在线视频| 精品国产91久久久久久| 日韩欧美在线看| 亚洲欧美激情精品一区二区| 成人在线免费观看视视频| 亚洲欧洲视频在线| 国产va免费精品高清在线| 久久免费少妇高潮久久精品99| 2019精品视频| 超在线视频97| 久久久久久久久久久免费| 91亚洲精品在线| 亚洲专区在线视频| 亚洲欧美国产日韩天堂区| 欧美激情视频网址| 欧美久久精品午夜青青大伊人| 亚洲色无码播放| 欧美精品18videos性欧美| 日本免费久久高清视频| 成人日韩av在线| 91色琪琪电影亚洲精品久久| 久久香蕉精品香蕉| 国产精品中文字幕在线| www.久久久久久.com| 91国在线精品国内播放| 色综合伊人色综合网| 孩xxxx性bbbb欧美| 性色av一区二区咪爱| 亚洲影院色在线观看免费| 亚洲男人av电影| 欧美一级高清免费播放| 久久综合国产精品台湾中文娱乐网| 欧美激情2020午夜免费观看| 操人视频在线观看欧美| 欧美精品中文字幕一区| 亚洲国产成人久久| 国产69精品久久久| 7777精品久久久久久| 国产成人综合精品在线| 91国语精品自产拍在线观看性色| 97在线视频观看| 在线播放日韩专区| 777午夜精品福利在线观看| 国产精品www色诱视频| 国产精品日韩一区| 亚洲国产精品一区二区久| 欧美激情第三页| 日韩黄在线观看| 在线观看中文字幕亚洲| 国产精品欧美一区二区三区奶水| 日韩在线免费视频观看| 少妇av一区二区三区| 国产一区二区久久精品| 国产精品久久久久不卡| 一区二区国产精品视频| 久久久久久网址| 欧美日韩中文字幕日韩欧美| 国产日韩一区在线| 国产suv精品一区二区三区88区| 久久久久久噜噜噜久久久精品| 一本色道久久综合狠狠躁篇怎么玩| 亚洲精品成人久久电影| 日韩大片在线观看视频| 欧美日韩国产一区中文午夜| 日本一区二区在线免费播放| 成人国产精品色哟哟| 日韩在线观看免费全集电视剧网站| 欧美一级免费看| 狠狠躁天天躁日日躁欧美| 国产精品久久久久7777婷婷| 欧美另类精品xxxx孕妇| 日韩av电影中文字幕| 日韩成人激情影院| 亚洲女人被黑人巨大进入al| 国产不卡视频在线| 正在播放欧美视频| 国产精品久久久久免费a∨| 欧美激情精品久久久久久变态| 中文字幕一区二区三区电影| 欧美激情一区二区久久久| 狠狠综合久久av一区二区小说| 亚洲影院污污.| 亚洲精品在线视频| 欧美电影免费观看高清| 中文字幕亚洲欧美在线| 精品毛片网大全| 91精品国产色综合| 亚洲成色777777在线观看影院| 国产精品高清免费在线观看| 91久久久久久久一区二区| 亚洲精品久久久久中文字幕二区| 69**夜色精品国产69乱| 蜜臀久久99精品久久久久久宅男| 久久精品视频播放| 原创国产精品91| 在线观看日韩av| 日本欧美一二三区| 伊人伊成久久人综合网站| 欧美性生交xxxxx久久久| 国产日韩欧美一二三区| 亚洲色图25p|