iOS 单例模式

前言:

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

要点:

显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

一、单例的优缺点

1.单例的优点(主要优点)

实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例
因为其上面的特点,对于项目中的个别场景的传值,存储状态等等更加方便

2.单例的缺点(主要缺点)
单例实例一旦创建,对象指针是保存在静态区的,那么在堆区分配空间只有在应用程序终止后才会被释放
单例不能继承

二、单例的几种写法

OC

1.静态指针方式(单线程模式单例)

///.h
@interface SingleExample : NSObject

+ (instancetype)sharedInstance;

@property (nonatomic, copy) NSString *order_id;

@end

///.m
#import "SingleExample.h"

@implementation SingleExample

+ (instancetype)sharedInstance{
    static SingleExample *myInstance = nil;
    if(myInstance == nil){
        myInstance = [[SingleExample alloc]init];
    }
    return myInstance;
}
@end

///测试
SingleExample *model = [SingleExample sharedInstance];
model.order_id = @"0001";
NSLog(@"------%@-------",model.order_id)

2.多线程加锁单例

/**
dispatch_once 无论使用多线程还是单线程,都只执行一次
GCD创建单例不仅可以解决多条线程的线程安全问题,也能保证性能,是官方荐的方式。
dispatch_once主要是根据onceToken的值来决定怎么去执行代码。
当onceToken = 0时,线程执行dispatch_once的block中代码
当onceToken =- 1时,线程跳过dispatch_once的block中代码不执行
当onceToken为其他值时,线程被阻塞,等待onceToken值改变

dispatch_once执行的流程
当线程调用shareInstance,此时onceToken = 0,调用block中的代码。此onceToken的值变为72。
当其他线程再调用shareInstance方法时,onceToken的值已经是72了,线程阻塞。
当block线程执行完block之后,onceToken变为-1.其他线程不再阻塞,跳过block。
下次再调用shareInstance时,block已经为-1.直接跳过block。
 */

///.h
@interface SingleExample : NSObject

+ (SingleExample *)shareInstance;

@property (nonatomic, copy) NSString *order_id;

@end

@implementation ShareManage

///.m
+ (SingleExample *) shareInstance {
    
    static SingleExample * single = nil;
    static dispatch_once_t onceToken ;
    
    NSLog(@"onceToken开始::::::%ld",onceToken);
    dispatch_once(&onceToken, ^{
        
        shareInstance =[[SingleExample alloc]init];
        NSLog(@"onceToken执行中::::::%ld",onceToken);
       // [NSThread sleepForTimeInterval:10];
        
    }) ;
    NSLog(@"onceToken执行结束::::::%ld",onceToken);
    return shareInstance;
    
}

@end

///测试
SingleExample *model = [SingleExample shareInstance];
model.order_id= @"0002";
NSLog(@"------%@-------",model.order_id)

3.单例的健壮性

///.h
@interface ShareManage : NSObject

+ (instancetype)shareManager;

@property (nonatomic, strong) NSString *NAME;

@end

///.m
#import "ShareManage.h"

@interface ShareManage()<NSCopying,NSMutableCopying>

@end

static ShareManage *manager = nil;

@implementation ShareManage

+ (instancetype)shareManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc]init];
        //不是使用alloc方法,而是调用[[super allocWithZone:NULL] init]
        //已经重载allocWithZone基本的对象分配方法,所以要借用父类(NSObject)的功能来帮助出处理底层内存分配的杂物
    });
    return manager;
}

///用alloc返回也是唯一实例
+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}

///对对象使用copy也是返回唯一实例
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return manager;
}

 ///对对象使用mutablecopy也是返回唯一实例
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return manager;
}
/*
 
 当static关键字修饰局部变量时,只会初始化一次且在程序中只有一份内存
 allocWithZone mutablecopyWithZone 这个类遵守<NSCopying,NSMutableCopying>协议
 如果_instance = [self alloc] init];创建的话,
 将会和-(id) allocWithZone:(struct _NSZone *)zone产生死锁。
 dispatch_once中的onceToken线程被阻塞,等待onceToken值改变。
 当用alloc创建对象、以及对对象进行copy mutableCopy也是返回唯一实例
 
 */
@end

///测试
ShareManage *manage = [ShareManage shareManager];
manage.NAME = @"测试单例,输出名称";
NSLog(@"------%@-------",manage.NAME)

Swift

1.最简单的 全局变量方法(“单行单例”方法) 通过 static 关键字创建

class SingletonOne {
    static let sharedInstance = SingletonOne()
    private init() {} 
    //切记私有化初始化方法,防止外部通过init直接创建实例。
}

2.严格单例模式 继承自 NSObject

class SingletonClass: NSObject {

    static let shared = SingletonClass()
    
    // Make sure the class has only one instance
    // Should not init or copy outside
    private override init() {}
    
    override func copy() -> Any {
        return self // SingletonClass.shared
    }
    
    override func mutableCopy() -> Any {
        return self // SingletonClass.shared
    }
    
    // Optional
    func reset() {
        // Reset all properties to default value
    }
}
/**
静态属性 shared 持有唯一的实例,对外公开。

重载 init() 方法,使其对外不可见,不可以在外部调用,防止在外部创建实例。

重载 copy()、mutableCopy() 方法,返回 self,防止在外部复制实例。这里也可以返回 SingletonClass.shared,效果是一样的,因为只有一个实例。只有 shared 能调用 copy()、mutableCopy() 方法,那么 self 就是 shared。写 self,代码比较简洁。

单例一旦创建,一直持有,不能手动销毁,但可以重置数据。如果需要的话,可以添加一个重置数据的方法 reset()。例如,当前用户退出登录,需要把当前用户实例的所有属性重置为默认值,防止数据错误。

*/

3.不继承自 NSObject

class SingletonClass2 {
    
    static let shared = SingletonClass2()
    
    // Make sure the class has only one instance
    // Should not init outside
    private init() {}
    
    // Optional
    func reset() {
        // Reset all properties to default value
    }
}
///不继承自 NSObject 的类没有 copy()、mutableCopy() 方法,不需要重载。

4.方法内定义静态常量

class SingleFour :NSObject{
 
    var tValue = "df"

    static var sharedInstance : SingleFour {
        struct Static {
            static let instance : SingleFour = SingleFour()
        }
        return Static.instance
    }
}

或

class ShareManage: NSObject {

    var tValue = "df"

    class var shareOnce : ShareManage {
        struct tOnce {
            static let instance = ShareManage()
        }
        return tOnce.instance
    }

}

///测试
ShareManage.sharedInstance.tValue = "1001"
print("123456789" + ShareManage.sharedInstance.tValue)

5.全局的常量

let single = SingleSix()
 
class SingleSix {
 
    var tValue = "df"
    class var sharedInstance : SingleSix {
        return single
    }
}

///测试
ShareManage.sharedInstance.tValue = "1001"
print("123456789" + ShareManage.sharedInstance.tValue)

6.使用GCD技术实现的单例模式 使用dispatch_once可以保证其中的代码只执行一次

/**
class SwiftSingleton {
    class var shared: SwiftSingleton {
        dispatch_once(&Inner.token) {
            Inner.instance = SwiftSingleton()
        }
        return Inner.instance!
    }
    struct Inner {
        static var instance: SwiftSingleton?
        static var token: dispatch_once_t = 0
    }
}
///swift3.0之后 dispatch_once_t、dispatch_once不可用。修改为下面代码
*/

var sharedInstance : ShareManage  {
    
    struct Inner {

        static var instance: ShareManage?
        static var token = {0}()
    }
    
    _ = Inner.token
    
    return Inner.instance!
 
}


class ShareManage {
    static let sharedInstance: ShareManage = { ShareManage() }()
    
    var shareName = ""
}

///测试
ShareManage.sharedInstance.shareName = "100"
print("123456789" + ShareManage.sharedInstance.shareName)

三、系统中的单例

UIApplication(应用程序实例)
NSNotificationCenter(消息中心):
NSFileManager(文件管理):
NSUserDefaults(应用程序设置):
NSURLCache(请求缓存):
NSHTTPCookieStorage(应用程序cookies池):

END

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

推荐阅读更多精彩内容

  • 简介: 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统...
    RunnerFL阅读 632评论 0 0
  • 本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗...
    水中的蓝天阅读 1,242评论 0 3
  • IOS单例模式(Singleton)单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例...
    Living_元宝儿阅读 1,339评论 1 6
  • 单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称...
    Lee坚武阅读 1,147评论 0 49
  • 单例模式大概是设计模式种较简单的一种设计模式。但在实际的开发过程中仍然存在一些坑。所以本文总结了下iOS中的单例模...
    CrazyItCoder阅读 1,314评论 0 4