Skip to content

tekizhong/DesignPattern-Singleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

DesignPattern-Singleton

#引言

最近在用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的链接地址。

About

设计模式之单例模式——第七章单例模式

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published