美文网首页
iOS设计模式——单例模式的使用

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

作者: iOS代码搬运工 | 来源:发表于2019-04-11 16:05 被阅读0次

    引言

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

    相关文章

      网友评论

          本文标题:iOS设计模式——单例模式的使用

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