哥的单例是伪的还是真的有图为证(Singleton)

前言


前段时间和同事交流单例模式,感觉自己对单例了解还有很多不足。上网查了下发现,有些帖子太坑,拿着伪单例大书特书,看着眼疼。
单例不是简单的编程技巧,它是编程模式,能上升到模式级别的东西,不是说几行简单代码能搞定的,每次听到“单例模式是设计模式中最简单的形式”这句话时,都有种想拿人撞墙的感觉。

什么是单例模式


提到单例,如果在大学里上Java课的时候,你忘了睡觉,那么你肯定知道单例有很多种写法,比如:饿汉式、懒汉式等。单例类的写法也是很多公司,笔试必考题之一。在iOS系统为我们提供了许多单例类,如,UIApplication、NSUserDefaults等。

单例模式是一个Class在系统中只允许生成一个Instance Object,以共享内存的方式供系统中其他实例对象进行访问。在iOS开发中,单例模式是非常有用的一种设计模式。

提到单例,很多人都会举一个例子,
具体场景:一台机器多个可打印的应用Pro1、 Pro2、Pro3......,一台打印机Print;
在多个应用连接打印机的时候,Pro1、 Pro2、Pro3连接打印机Print的时候,生成的Print实例是同一个实例。

单例的作用


  1. 单例类保证了应用程序的生命周期中有且仅有一个该类的实例对象,而且易于外界访问。
  2. 共享内存,存储用户数据等
  3. 无交互类传值时,充当中间人

写法分类:


  1. 懒汉式 : 首次用到单例对象的时,创建实例对象;
  2. 饿汉式 : 进入程序就创建实例对象

提到这两种方式,首先说个知识点:NSObject的load和initialize方法,点开Apple官方关于NSObject的API会发现,在NSObject.h文件中有两个类方法load、initialize,

@interface NSObject <NSObject> 
{
    Class isa  OBJC_ISA_AVAILABILITY;
}
+ (void)load;
+ (void)initialize;

The load message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.
The order of initialization is as follows:
All initializers in any framework you link to.
All +load methods in your image.
All C++ static initializers and C/C++ attribute(constructor) functions in your image.
All initializers in frameworks that link to you.

The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses. The superclass implementation may be called multiple times if subclasses do not implement initialize—the runtime will call the inherited implementation—or if subclasses explicitly call [super initialize].

Apple的官方文档清楚地说明了initialize和load的区别:
load:只要类所在文件被引用就会被调用,即文件的.m文件引入,系统运行,load就会被执行;
initialize:在类或者其子类的方法被调用前被调用,它属于懒汉的,自己的方法没被用到,它是不会执行的。

相同点:两种方法都只会被调用一次。

为了防止不停的if -->( _instance == nil) else ....这种令人作呕的判断,下面实现使用线程方式(记得实现NSCopying, NSMutableCopying协议方法):

先验证下,哥的单例是伪的,还是真的,有图为证:

有朋友问到,使用alloc创建实例为什么会地址相同,主要是因为重写了allocWithZone,返回同一个实例。后面mutableCopyWithZone和copyWithZone方法的重写,是即便是使用copy修饰,也同样返回同一个实例。

@property (nonatomic, copy) EVNHelper *helper;

懒汉式单例

.h文件:

//
//  EVNHelper.h
//  MMBao_master
//
//  Created by developer on 16/6/11.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface EVNHelper : NSObject<NSCopying, NSMutableCopying>

+ (instancetype)shareInstance;

@end

.m文件:

//
//  EVNHelper.m
//  MMBao_master
//
//  Created by developer on 16/6/11.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import "EVNHelper.h"

static id _instance;

@implementation EVNHelper
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}
@end

饿汉式单例

.h文件:

//
//  EVNHelper.h
//  MMBao_master
//
//  Created by developer on 16/6/11.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface EVNHelper : NSObject<NSCopying, NSMutableCopying>

+ (instancetype)shareInstance;

@end

.m文件:

//
//  EVNHelper.m
//  MMBao_master
//
//  Created by developer on 16/6/11.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import "EVNHelper.h"

static id _instance;

@implementation EVNHelper

 /**
 *  只要系统中引用了该类,程序运行,就会主动调用load(不用手动调用,而且只会加载1次)
 */
+ (void)load
{
    _instance = [[EVNHelper alloc] init]; //[[self alloc] init];
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}
@end

上面的写法是在ARC情况下,MRC还需在.m文件中添加如下方法:(鄙人不太懂MRC,只为扩充下,有问题,请回复,指教)

(1) 重写release方法为空
(2) 重写retain方法返回self
(3) 重写retainCount返回 1
(4) 重写autorelease返回self

- (oneway void)release
{ 
    NSLog(@"这里空语句就行");
}
- (id)retain 
{
    return self;
}
- (NSUInteger)retainCount
{
     return 1;
}
- (id)autorelease 
{
   return self;
}

本文已在版权印备案,如需转载请在版权印获取授权。
获取版权

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

推荐阅读更多精彩内容