iOS 单例模式实现

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢。

单例模式,由于其使得类的一个对象成为系统中的唯一实例,同时提供了对唯一实例的受控访问,是在开发中常用的设计模式,本文主要记录我自己在开发中如何使用单例并手动销毁的。

单例模式是什么

  • 单例模式定义:简单的来说,一个单例类,在整个程序中只有一个实例,并且提供一个类方法供全局调用,在编译时初始化这个类,然后一直保存在内存中,程序(APP)退出时由系统自动释放这部分内存。

系统常见的单例

UIApplication                     (应用程序实例类)

NSNotificationCenter              (消息中心类)

NSFileManager                     (文件管理类)

NSUserDefaults                    (应用程序设置)

NSURLCache                        (请求缓存类)

NSHTTPCookieStorage               (应用程序cookies池)

单例的应用场景

(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。

(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

单例的生命周期

请看下面的表格展示了程序中中不同的变量在手机存储器中的存储位置

内存分配.png

在程序中,一个单例类在程序中只能初始化一次,为了保证在使用中始终都是存在的,所以单例是在存储器的全局区域,在编译时分配内存,只要程序还在运行就会一直占用内存,在APP结束后由系统释放这部分内存内存。

新建一个单例类

  • 单例模式的创建方式
同步锁 :NSLock

@synchronized(self) {}

信号量控制并发:dispatch_semaphore_t

条件锁:NSConditionLock

GCD  :  dispatch_once_t

其中采用GCD 创建单例是线程安全,苹果官方推荐开发者使用dispatch_once_t来创建单例,那么我就采用dispatch_once_t方法来创建一个单例, 类名为ASharedManage。

由于一个继承自NSObject的对象可以通过多种方式创建如:alloc 、new 、copy、mutableCopy . 如果同事用在项目中用到了这个类,又不知道这是一个单例,他通过alloc init 来创建出来这个对象就跟通过sharedManage方法创建出来的不是同一对象了,这不是我们想看到的结果,所以需要重写这些方法来保证不论通过哪种方式创建出来的必须为同一对象。如:

//单利方法
+ (instancetype)shareInstance {
   //注意下面这行代码直接写在这里就可以,不用担心多次调用出问题;1.static id instance = nil;只是编一阶段的初始值,真正赋值后就是一个唯一的值 2. onceToken地址没有被释放就不会再次进入dispatch_once函数
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}

//alloc new 方式创建实例最终都会执行这个方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [[self class] shareInstance];
}
//copy mutableCopy 方式创建实例最终都会执行这个方法
- (instancetype)copyWithZone:(struct _NSZone *)zone{
    return [[self class] shareInstance];
}

补充:static可以多次赋值,但最好不要那么做,负责会失去静态变量的意义

测试单利是否有效 ???

ASharedManage *manage1 = [[ASharedManage alloc]init];
ASharedManage *manage2 = [[ASharedManage alloc]init];
ASharedManage *manage3 = [[ASharedManage alloc]init];
ASharedManage *manage4 = [ASharedManage sharedLoginQuery];
ASharedManage *manage5 = [ASharedManage sharedLoginQuery];
ASharedManage *manage6 = [ASharedManage sharedLoginQuery];
ASharedManage *manage7 = [manage6 copy];
ASharedManage *manage8 = [manage5 copy];

manage1 0x6000029884f0
manage2 0x6000029884f0
manage3 0x6000029884f0
manage4 0x6000029884f0
manage5 0x6000029884f0
manage6 0x6000029884f0
manage7 0x6000029884f0
manage8 0x6000029884f0

如此就可以保证创建出来的是同一的实例了 !

单例的优缺点

主要优点:

1、提供了对唯一实例的接受访问。

2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

3、允许可变数目的实例。

主要缺点:

1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

2、单例类的职责过重,在一定程度上违背了“单一职责原则”。

3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

单例宏定义

由于单例对象在开发中可能用到的不止一次,实现方式都一样,所以抽取成为宏来使用就成为必不可少的操作。代码如下:

#define ASingleH(className)\

+(instancetype)share##className;\

+(void)destruction##className;\

#if __has_feature(objc_arc)

#define ASingleM(className) static id _instance;\

static dispatch_once_t aonceToken;\

+(instancetype)allocWithZone:(struct _NSZone *)zone\

{\

static dispatch_once_t onceToken;\

dispatch_once(&onceToken, ^{\

_instance = [super allocWithZone:zone];\

});\

return _instance;\

}\

\

+(instancetype)share##className\

{\

static dispatch_once_t onceToken;\

dispatch_once(&onceToken, ^{\

_instance = [[className alloc]init];\

});\

return _instance;\

}\

-(id)copyWithZone:(NSZone *)zone\

{\

return _instance;\

}\

+(instancetype)alloc{\

if(_instance)\

{ return  _instance;\

}\

return [super alloc];\

}\

-(instancetype)init{\

if(_instance)\

{  return  _instance;}\

return [super init];\

}\

-(id)copy{\

if(_instance)\

{\

return  _instance;\

}\

return [super copy];\

}\

- (id)mutableCopy\

{\

if(_instance)\

{\

return  _instance;\

}\

return [super copy];\

}\

+(void)destruction##className{\

    _instance = nil;\

    aonceToken =0l;\

}

#endif

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容