单例模式

作者: bingxuePI | 来源:发表于2017-04-05 10:54 被阅读3次

@synchronized

  1. 定义一个静态的全局的变量
    static Settings *sharedSettings = nil;

  2. 创建一个类方法,用来返回该类实例
    synchronized 这个主要是考虑多线程的程序,这个指令可以将{ } 内的代码限制在一个线程执行,如果某个线程没有执行完,其他的线程如果需要执行就得等着。

 + (Settings *)sharedInstance {
@synchronized(self){
if(sharedSettings  ==  nil){
            sharedSettings = [[self alloc] init];
          //做一些初始化操作
        }
    }
return  sharedSettings;
}
  1. 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
 + (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
        if (sharedSettings == nil) {
            sharedSettings = [super allocWithZone:zone];
        }
    }
    return sharedSettings;
}

dispatch_once
有些变量只需要初始化一次(如从文件中读取配置参数,读取设备型号等等),可以使用dispatch_once来进行读取优化,保证只调用API一次,以后就只要直接访问变量即可
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如
@synchronized之类的来防止使用多个线程或者队列时不同步的问题。

//范例如下:
static BOOL isTestMode;

+ (BOOL)isTestMode {

  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
  NSNumber* obj = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFResourceTest"];
  isTestMode = [obj boolValue];
    });

  return isTestMode;
}

实际要如何使用这些呢?
好吧,假设有一个AccountManager类,你想在整个应用中访问该类的共享实例。你可以按如下代码简单实现一个类方法:

+ (AccountManager *)sharedManager {

  static AccountManager *sharedAccountManagerInstance = nil;
  static dispatch_once_t predicate;
  dispatch_once(&predicate, ^{
        sharedAccountManagerInstance = [[self alloc] init];
    });
  return sharedAccountManagerInstance;
}

这就意味着你任何时候访问共享实例,需要做的仅是:

AccountManager *accountManager = [AccountManager sharedManager];
该方法有很多优势
a. 线程安全
b. 很好满足静态分析器要求
c. 和自动引用计数(ARC)兼容
d. 仅需要少量代码

就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。

该方法有很多优势
a. 线程安全
b. 很好满足静态分析器要求
c. 和自动引用计数(ARC)兼容
d. 仅需要少量代码

该方法的劣势就是它仍然运行创建一个非共享的实例:我们通常在OC中实现一个单例方法都是这样:

static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });
    return instance;
}

可是这样就可以了么?我做了如下测试:

HLTestObject *objct1 = [HLTestObject sharedInstance];
NSLog(@"%@",objct1);
HLTestObject *objc2 = [[HLTestObject alloc] init];
NSLog(@"%@",objc2);
HLTestObject *objc3 = [HLTestObject new];
NSLog(@"%@",objc3);

看到这个测试,你想到打印结果了么?结果是这样的:

2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf39515510>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c4b70>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c4b70></hltestobject: 0x7fcf39515510>

很明显,通过三种方式创建出来的是不同的实例对象,这就违背了单例类有且仅有一个实例的定义。

为了防止别人不小心利用alloc/init方式创建示例,也为了防止别人故意为之,我们要保证不管用什么方式创建都只能是同一个实例对象,这就得重写另一个方法,实现如下:

static TYGAreaPickerView *sharedObject = nil;
+ (TYGPlaceholderHelper *)sharedInstance {

    static dispatch_once_t _singletonPredicate;
    dispatch_once(&_singletonPredicate, ^{
        sharedObject = [[super allocWithZone:nil] init];
    });
    return sharedObject;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [self sharedInstance];
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
        instance.height = 10;
        instance.object = [[NSObject alloc] init];
        instance.arrayM = [[NSMutableArray alloc] init];
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {
    return [[self alloc] init];
}
- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super init];
        instance.height = 10;
        instance.object = [[NSObject alloc] init];
        instance.arrayM = [[NSMutableArray alloc] init];
    });
    return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}

相关文章

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • IOS单例模式的底层原理

    单例介绍 本文源码下载地址 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一...

  • 单例

    iOS单例模式iOS之单例模式初探iOS单例详解

  • 单例模式

    单例模式1 单例模式2

  • java的单例模式

    饿汉单例模式 懒汉单例模式

网友评论

    本文标题:单例模式

    本文链接:https://www.haomeiwen.com/subject/pnytattx.html