iOS设计模式——单例模式的使用

2019-04-11  本文已影响0人  iOS代码搬运工

引言

最近在用xib拖入Object的时候发现一个问题,xib各连线正常,但是死活不调用单例中的方法。经过一步步排查,检查出原来是单例模式出了问题。特此记录下。

1、何为单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2、何时使用单例模式

在以下情形,应该考虑使用单例模式:

3、使用OC实现单例模式

.h

@interface TKSingleton : NSObject<NSCopying>

@property (nonatomic, readonly)  UIViewController *activityViewController;
@property (nonatomic, readonly) RootViewController *rootViewController;

+ (TKSingleton *) sharedInstance;
@end

.m

@interface TKSingleton()
- (void)initialize;
@end

@implementation TKSingleton

static TKSingleton *tkSingleton_ = nil;

+ (TKSingleton *)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tkSingleton_ = [[self alloc] init];
        [tkSingleton_ initialize];
    });
    return tkSingleton_;
}

- (void)initialize {
    _rootViewController = [[RootViewController alloc] init];
    _activityViewController = _rootViewController;
}

@end

这是我们通常的写法,乍一看也没什么毛病(之前我也是这么写的导致后面没有调用单例中的方法)。如果真是这样的话,那么就没必要写这个文章记录了。但实际上,需要克服一些障碍才能让实现足够可靠,可以用在真正的应用程序中。如果需要实现单例模式中的“严格”版本,要想在实际中使用,需要面对一下两个主要的障碍:

@interface TKSingleton()
- (void)initialize;
@end

@implementation TKSingleton

static TKSingleton *tkSingleton_ = nil;

+ (TKSingleton *)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tkSingleton_ = [[super allocWithZone:NULL] init];
        [tkSingleton_ initialize];
    });
    return tkSingleton_;
}

- (void)initialize {
    _rootViewController = [[RootViewController alloc] init];
    _activityViewController = _rootViewController;
}


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

- (id)copyWithZone:(NSZone *)zone {
    return [TKSingleton sharedInstance];
}

@end

关于单例模式的初始化,官方推荐使用GCD。不仅可以解决多条线程的线程安全问题,也能保证性能。在shareInstance方法中,跟第一个例子一样,首先检查类的唯一实例是否已经创建,如果没有,就创建新的实例并将其返回。但是这回,他不是使用alloc这样的方法,而是调用[[super allocWithZone:NULL] init]来生成新的实例。为什么是super而不是self呢?这是因为在self中重载了基本的对象分配方法,所以需要“借用”其父类(即NSObject)的功能,来帮助处理底层内存分配的杂务。
allocWithZone:(struct _NSZone *)zone方法中,只是返回从sharedInstance方法返回的类实例。在Cocoa Touch框架中,调用类的allocWithZone:(struct _NSZone *)zone方法,会分配实例的内存,引用计数会置为1,然后会返回实例。类似地,需要重载copyWithZone:(NSZone *)zone方法,以保证不会返回实例的副本,而是通过返回[TKSingleton sharedInstance]返回同一个实例。

4、解决方案

回到之前提出的问题,解决的方案就是将tkSingleton_ = [[self alloc] init];替换成tkSingleton_ = [[super allocWithZone:NULL] init]; 并增加allocWithZone:(struct _NSZone *)zone方法。

附上Demo的链接地址。

上一篇 下一篇

猜你喜欢

热点阅读