美文网首页
iOS中的单例以及安全写法

iOS中的单例以及安全写法

作者: 炒河粉儿 | 来源:发表于2019-08-03 16:31 被阅读0次

保证一个类只有一个实例,并且提供一个全局访问的入口访问这个实例。

普通写法

+ (DJSingleton *)shareInstance{
    static DJSingleton * s_instance_dj_singleton = nil ;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (s_instance_dj_manager == nil) {
            s_instance_dj_manager = [[DJSingleton alloc] init];
        }
    });
    return (DJSingleton *)s_instance_dj_singleton;
}

设置一个静态变量,一个类方法,使用GCD加锁,解决对线程同时访问的问题。

合作开发中 别人不知道你这个是个单例 他如果不是用这个类方法创建对象,而使用alloc或者new的方法就会出现问题了。

方式一
由Objective-C的一些特性可以知道,在对象创建的时候,无论是alloc还是new,都会调用到 allocWithZone方法。在通过拷贝的时候创建对象时,会调用到-(id)copyWithZone:(NSZone *)zone,-(id)mutableCopyWithZone:(NSZone *)zone方法。因此,可以重写这些方法,让创建的对象唯一。

+(id)allocWithZone:(NSZone *)zone{
    return [DJSingleton sharedInstance];
}
+(DJSingleton *) sharedInstance{
    static DJSingleton * s_instance_dj_singleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        s_instance_dj_singleton = [[super allocWithZone:nil] init];
    });
    return s_instance_dj_singleton;
}
-(id)copyWithZone:(NSZone *)zone{
    return [DJSingleton sharedInstance];
}
-(id)mutableCopyWithZone:(NSZone *)zone{
    return [DJSingleton sharedInstance];
}

方式二
温柔派就直接告诉外面,alloc,new,copy,mutableCopy方法不可以直接调用。否则编译不过。

+(instancetype) alloc __attribute__((unavailable("call sharedInstance instead")));
+(instancetype) new __attribute__((unavailable("call sharedInstance instead")));
-(instancetype) copy __attribute__((unavailable("call sharedInstance instead")));
-(instancetype) mutableCopy __attribute__((unavailable("call sharedInstance instead")));

在方便一点 写成宏

#define DJ_SINGLETON_DEF(_type_) + (_type_ *)sharedInstance;\
+(instancetype) alloc __attribute__((unavailable("call sharedInstance instead")));\
+(instancetype) new __attribute__((unavailable("call sharedInstance instead")));\
-(instancetype) copy __attribute__((unavailable("call sharedInstance instead")));\
-(instancetype) mutableCopy __attribute__((unavailable("call sharedInstance instead")));\
#define DJ_SINGLETON_IMP(_type_) + (_type_ *)sharedInstance{\
static _type_ *theSharedInstance = nil;\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
theSharedInstance = [[super alloc] init];\
});\
return theSharedInstance;\
}

那么,在定义和实现的时候就很简单了:

@interface DJSingleton : NSObject
    DJ_SINGLETON_DEF(DJSingleton);
@end
@implementation DJSingleton
    DJ_SINGLETON_IMP(DJSingleton);
@end
  1. 内存问题
    单例模式实际上延长了对象的生命周期。那么就存在内存问题。因为这个对象在程序的整个生命都存在。所以当这个单例比较大的时候,总是hold住那么多内存,就需要考虑这件事了。另外,可能单例本身并不大,但是它如果强引用了另外的比较大的对象,也算是一个问题。别的对象因为单例对象不释放而不释放。
    当然这个问题也有一定的办法。比如对于一些可以重新加载的对象,在需要的时候加载,用完之后,单例对象就不再强引用,从而把原先hold住的对象释放掉。下次需要再加载回来。
  2. 循环依赖问题
    在开发过程中,单例对象可能有一些属性,一般会放在init的时候创建和初始化。这样,比如如果单例A的m属性依赖于单例B,单例B的属性n依赖于单例A,初始化的时候就会出现死循环依赖。死在dispatch_once里。
@interface DJSingletonA : NSObject
    DJ_SINGLETON_DEF(DJSingletonA);
@end
@interface DJSingletonB : NSObject
    DJ_SINGLETON_DEF(DJSingletonB);
@end
@interface DJSingletonA()
@property(nonatomic, strong) id someObj;
@end
@implementation DJSingletonA
DJ_SINGLETON_IMP(DJSingletonA);
-(id)init{
    if (self = [super init]) {
        _someObj = [DJSingletonB sharedInstance];
    }
    return self;
}
@end
@interface DJSingletonB()
@property(nonatomic, strong) id someObj;
@end
@implementation DJSingletonB
DJ_SINGLETON_IMP(DJSingletonB);
-(id)init{
    if (self = [super init]) {
        _someObj = [DJSingletonA sharedInstance];
    }
    return self;
}
@end
//---------------------------------------
DJSingletonA * s1 = [DJSingletonA sharedInstance];

对于这种情况,最好的设计是在单例设计的时候,初始化的内容不要依赖于其他对象。如果实在要依赖,就不要让它形成环。实在会形成环或者无法控制,就采用异步初始化的方式。先过去,内容以后再填。内部需要做个标识,标识这个单例在造出来之后,不能立刻使用或者完整使用。

相关文章

  • iOS中的单例以及安全写法

    保证一个类只有一个实例,并且提供一个全局访问的入口访问这个实例。 普通写法 设置一个静态变量,一个类方法,使用GC...

  • iOS 单例模式

    关于单例模式的详解,看完这几篇,就完全了然了。iOS 单例模式iOS中的单例模式iOS单例的写法

  • 单例写法

    1.基于线程安全的单例写法 2.基于加锁的单例写法

  • iOS单例安全写法

    单例模式很常见,但是,能真正把单利模式写对的却很少。在iOS中,一般我们都是用官方推荐的写法来写单例: 这也是我们...

  • ios~单例模式:

    在iOS OC中,一般我们都是用官方推荐的写法来写单例:GCD方式单例 分析单例 static SharedPer...

  • 单例的写法以及线程安全

    单例模式,代表只需一个对象就可以,即某个类只需要一个实例。比如一台计算机连接多台打印机,但这个计算机上的打印程序只...

  • 11.1设计模式-单例模式-详解

    单例模式: 单例介绍 单例的六种写法和各自特点饿汉、懒汉、懒汉安全、DCL、静态内部类、枚举。 android中的...

  • 单例的2种写法

    单例模式是iOS开发中最常用的设计模式,iOS的单例模式有两种官方写法,如下: 1,常用写法 import "Se...

  • 关于单例模式的思考

    饿汉式单例模式(写法一) /** * 饿汉式单例 写法一 * 优点:简单,性能高,线程安全 * 缺点:浪费内存(当...

  • iOS中的单例写法

    另一种使用GCD:

网友评论

      本文标题:iOS中的单例以及安全写法

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