iOS中的单例

112 阅读2分钟

什么是单例

单例模式:一种常见的软件设计模式,通过单例模式的方法创建的类在当前进程中只有一个实例。如:
UIApplication
NSNotificationCenter
NSUserDefault

单例模式的优点

1、单例可以保证系统中该类有且仅有一个实例,确保所有对象都访问这个唯一实例。
2、因为只有一个实例,减少了内存开发和系统的性能开销。

单例模式的缺点

1、可扩展性比较差。
2、实例一旦被创造,分配的空间只有在 App 结束之后才会被释放。
3、滥用导致不相关的类产生的耦合问题。

OC单例的实现方法

经典写法

@implementation YZSingleton
    // static 全局的变量
    // static 修饰的变量存储在静态存储区,只会在程序结束之后才释放
    static YZSingleton *instance = nil;
    + (instancetype)sharedSingleton {
    // 线程不安全
        if (instance == nil) {
            instance = [[self alloc] init];
        }
        return instance;
    }

这种实现方式只适用于单线程,在多线程的情况下无法保证线程安全

线程同步


@implementation YZSingleton

// static 全局的变量
// static 修饰的变量存储在静态存储区,只会在程序结束之后才释放
static YZSingleton *instance = nil;
+ (instancetype)sharedSingleton {
    // 线程同步保证线程安全
    @synchronized (self) {
        if (instance == nil) {
            instance = [[self alloc] init];
        }
        return instance;
    }
}

这种实现方式保证多线程下也只有一个线程能进入

GCD 写法

@implementation YZSingleton
// static 全局的变量
// static 修饰的变量存储在静态存储区,只会在程序结束之后才释放
static YZSingleton *instance = nil;
+ (instancetype)sharedSingleton {
    // dispatch_once 本身就是线程安全
    // dispatch_once 执行时间要比 @synchronized 快
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[YZSingleton alloc] init];
    });
    return instance;
}

- (instancetype)copyWithZone:(NSZone *)zone {
// return [YZSingleton sharedSingleton];
    return instance;
}

- (instancetype)mutableCopyWithZone:(NSZone *)zone {
// return [YZSingleton sharedSingleton];
    return instance;
}

GCD 优化禁止外部调用

在.h 文件中禁止调用初始化方法

+ (instancetype)sharedSingleton;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
+ (instancetype)alloc NS_UNAVAILABLE;
- (id)copy NS_UNAVAILABLE;
- (id)mutableCopy NS_UNAVAILABLE;

.m 文件


@implementation YZSingleton

// static 全局的变量
// static 修饰的变量存储在静态存储区,只会在程序结束之后才释放
static YZSingleton *instance = nil;
+ (instancetype)sharedSingleton {
    // dispatch_once 本身就是线程安全
    // dispatch_once 执行时间要比 @synchronized 快
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

宏定义


#define YZ_SINGLETON_DEF(_type_) + (_type_ *)sharedSingleton; \
- (instancetype)init __attribute__((unavailable("请使用sharedSingleton"))); \
+ (instancetype)new __attribute__((unavailable("请使用sharedSingleton"))); \
+ (instancetype)alloc __attribute__((unavailable("请使用sharedSingleton"))); \
- (id)copy __attribute__((unavailable("请使用sharedSingleton"))); \
- (id)mutableCopy __attribute__((unavailable("请使用sharedSingleton"))); \

#define YZ_SINGLETON_IMP(_type_) + (instancetype)sharedSingleton { \
static _type_ *instance = nil; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [[super alloc] init]; \
}); \
return instance; \
}

使用:

@interface YZMarcoSingleton : NSObject

YZ_SINGLETON_DEF(YZMarcoSingleton);

@end


@implementation YZMarcoSingleton
YZ_SINGLETON_IMP(YZMarcoSingleton);
@end

Swift单例的实现方法

class YZSwiftSingleton {
    static let sharedSingleton = YZSwiftSingleton()
    private init(){}
    func foo() {
        print("foo-")
    }
}