设计模式 之 Singleton (Objective-C实现)

本文的完整代码在这里的DesignPatternDemo

目录

  • 初始版本

  • 同步锁版本

  • GCD版本

  • alloc版本

  • copy版本

  • 小结

引言

开发中最常见也是最简单的设计模式莫过于单例模式了

但是写好一个单例模式其实并没有那么简单

鉴于它的难易适中, 所以经常会出现在各种笔试面试题中

废话不多说, 我们来实际演练瞧瞧

初始版本

说写咱就写, 不出两分钟单例就写好了

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    if (!sharedInstance) {
        sharedInstance = [self new];
    }
    return sharedInstance;
}

接着我们来测试一下

SingletonClass *singletonObject = [SingletonClass sharedInstance];
NSLog(@"%p", singletonObject);
singletonObject = [SingletonClass sharedInstance];
NSLog(@"%p", singletonObject);

打印结果如下

0x7fab72708d90
0x7fab72708d90

同步锁版本

上面的写法, 没有考虑多线程并发问题, 所以我们加个同步锁

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    @synchronized(self) {
        if (!sharedInstance) {
            sharedInstance = [self new];
        }
    }
    return sharedInstance;
}

GCD版本

GCD提供了dispatch_once接口来保证代码只会被执行一次, 相比同步锁效率更高

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [self new];
    });
    return sharedInstance;
}

alloc版本

这下程序应该完美了, 可以收工了

别急, 万一别人是用这种方式获取SingletonClass对象的呢?

别为我为什么要用这个方式, 我还要问你别人为什么只使用sharedInstance方式呢!

SingletonClass *singletonObject = [SingletonClass sharedInstance];
NSLog(@"%p", singletonObject);
singletonObject = [[SingletonClass alloc] init];
NSLog(@"%p", singletonObject);

打印结果如下

0x7fb4d3f25140
0x7fb4d3e0c950

为了解决这个问题, 我们需要修改sharedInstance方法并覆盖allocWithZone方法

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });
    return sharedInstance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

重新运行测试用例, 打印结果如下

0x12dd2bcb0
0x12dd2bcb0

copy版本

这下程序应该完美了吧, 总算可以收工了吧

说了不要急, 我们还没有测试copy对象的情形呢

SingletonClass *copyedObject = [singletonObject copy];
NSLog(@"%p", copyedObject);

重新运行程序看下打印结果吧, 怎么样? crash了!

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SingletonClass copyWithZone:]: unrecognized selector sent to instance 0x14766dab0'

找不到copyWithZone方法, 说明我们也需要覆盖该方法

+ (id)copyWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

- (id)copy {
    return self;
}

这下再运行上面所有的测试用例

打印结果如下

0x136641720
0x136641720
0x136641720

小结

上述单例的写法已经可以满足大部分的需求了, 所以我们就不继续深究和完善了

小结个吧, 单例的完整定义如下

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });
    return sharedInstance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

+ (id)copyWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

- (id)copy {
    return self;
}

PS: 最后应该给单例模式一个权威定义的, 所以摘录Big Four的设计模式中的定义如下

Ensure a class has only one instance, and provide a global point of access to it.

确保某一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例

更多文章, 请支持我的个人博客

你可能感兴趣的:(设计模式 之 Singleton (Objective-C实现))