美文网首页iOSiOS学习搬砖
iOS 中的单例模式

iOS 中的单例模式

作者: 奋斗的菜鸟 | 来源:发表于2015-08-29 21:47 被阅读13588次

    在iOS中有很多单例对象,比如UIApplication,UIScreen等等,那我们自己可以实现单例吗?答案是肯定的,请往下看

    ARC中的单例实现
    //.h文件
    #import <Foundation/Foundation.h>
    @interface Singleton : NSObject
    //单例方法
    +(instancetype)sharedSingleton;
    @end
    //.m文件
    #import "Singleton.h"
    @implementation Singleton
    //全局变量
    static id _instance = nil;
    //单例方法
    +(instancetype)sharedSingleton{
        return [[self alloc] init];
    }
    ////alloc会调用allocWithZone:
    +(instancetype)allocWithZone:(struct _NSZone *)zone{
        //只进行一次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        return _instance;
    }
    //初始化方法
    - (instancetype)init{
        // 只进行一次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super init];
        });
        return _instance;
    }
    //copy在底层 会调用copyWithZone:
    - (id)copyWithZone:(NSZone *)zone{
        return  _instance;
    }
    + (id)copyWithZone:(struct _NSZone *)zone{
        return  _instance;
    }
    + (id)mutableCopyWithZone:(struct _NSZone *)zone{
        return _instance;
    }
    - (id)mutableCopyWithZone:(NSZone *)zone{
        return _instance;
    }
    @end
    
    • 测试代码及运行结果
    #import <Foundation/Foundation.h>
    #import "Singleton.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Singleton *s1 = [[Singleton alloc]init];
            Singleton *s2 = [Singleton sharedSingleton];
            
            Singleton *s3 = [[Singleton alloc]init];
            Singleton *s4 = [Singleton sharedSingleton];
            Singleton *s5 = [s4 copy];
            NSLog(@"%p %p %p %p %p",s1,s2,s3,s4, s5);
        }
        return 0;
    }
    运行结果
    2015-08-29 21:07:01.869 Singleton-ARC[42202:784939] 0x100114760 0x100114760 0x100114760 0x100114760 0x100114760
    
    非ARC中的单例实现
    • 因为在非ARC中,需要我们自己管理内存,所以实现稍微负责一点
    //.m文件
    #import <Foundation/Foundation.h>
    //单例方法
    @interface Singleton : NSObject
    + (instancetype)sharedSingleton;
    @end
    //.m文件
    #import "Singleton.h"
    
    @implementation Singleton
    //全局变量
    static id _instance = nil;
    //单例方法
    +(instancetype)sharedSingleton{
        //系统的大多数类方法都有做autorelease,所以我们也需要做一下
         return [[[self alloc] init] autorelease];
    }
    //alloc会调用allocWithZone:
    +(instancetype)allocWithZone:(struct _NSZone *)zone{
        //只进行一次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        return _instance;
    }
    //初始化方法
    -(instancetype)init{
        // 只进行一次
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super init];
        });
        return _instance;
    }
    - (oneway void)release{
        //什么都不做 保证单例对象不被销毁
    }
    //返回本身 保证只有一个单例对象
    - (instancetype)retain{
        return _instance;
    } 
    //计数器为1 保证只有一个单例对象
    - (NSUInteger)retainCount{
        return 1;
    }
    //copy在底层 会调用copyWithZone:
    + (id)copyWithZone:(struct _NSZone *)zone{
        return  _instance;
    }
    - (id)copyWithZone:(NSZone *)zone{
        return _instance;
    }
    + (id)mutableCopyWithZone:(struct _NSZone *)zone{
        return _instance;
    }
    - (id)mutableCopyWithZone:(NSZone *)zone{
        return _instance;
    }
    @end
    
    • 因为要保证单例对象在程序运行期间一直存在,所以不需要实现release方法和dealloc方法
    • 测试代码及运行结果
    #import <Foundation/Foundation.h>
    #import "Singleton.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Singleton *s1 = [[Singleton alloc]init];
            Singleton *s2 = [Singleton sharedSingleton];
            
            Singleton *s3 = [[Singleton alloc]init];
            Singleton *s4 = [Singleton sharedSingleton];
            Singleton *s5 = [s4 copy];
            
            
            NSLog(@"%p %p %p %p %p",s1,s2,s3,s4, s5);
            [s1 release];
            [s3 release];
            [s5 release];
            
        }
        return 0;
    }
    运行结果
    2015-08-29 21:01:43.770 Singleton-非ARC[42192:782473] 0x100206880 0x100206880 0x100206880 0x100206880 0x100206880
    
    • 也可以把上面的代码抽出一个宏,以ARC为例
    //.h文件   ##表示拼接字符
    #define SingletonH(methodName) +(instancetype)shared##methodName;
    //.m文件
    #define SingletonM(methodName)\
    \
    static id _instance = nil;\
    +(instancetype)sharedSingleton{\
        return [[self alloc] init];\
    }\
    +(instancetype)allocWithZone:(struct _NSZone *)zone{\
        static dispatch_once_t onceToken;\
        dispatch_once(&onceToken, ^{\
            _instance = [super allocWithZone:zone];\
        });\
        return _instance;\
    }\
    - (instancetype)init{\
        static dispatch_once_t onceToken;\
        dispatch_once(&onceToken, ^{\
            _instance = [super init];\
        });\
        return _instance;\
    }\
    - (id)copyWithZone:(NSZone *)zone{\
        return  _instance;\
    }\
    + (id)copyWithZone:(struct _NSZone *)zone{\
        return  _instance;\
    }
    
    • 以上代码如果有上面不对的地方,敬请纠正,谢谢!

    相关文章

      网友评论

      • 7529e3cee684:Do not override allocWithZone: to include any initialization code. Instead, class-specific versions of init... methods.

        This method exists for historical reasons; memory zones are no longer used by Objective-C.
        —— 苹果官方文档
      • 飞羽孟德:宏定义写错了
        static id _instance = nil;\
        +(instancetype)sharedSingleton{\
        return [[self alloc] init];\
        }\

        应该改为 shared##methodName
        WhatHurtsMore:两种写法 一个道理
      • 天真烂漫的孩子:ARC系统自动调用retain,release,不需要重写么?
        + (id)copyWithZone:(struct _NSZone *)zone这个类方法,也需要重写?

      本文标题:iOS 中的单例模式

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