iOS 单例模式首页投稿(暂停使用,暂停投稿)互联网科技

iOS中的单例模式

2016-03-23  本文已影响746人  Alexander

@WilliamAlex大叔

前言

目前流行的社交APP中都离不开单例的使用,我们来举个例子哈,比如现在流行的"糗事百科""美拍"等APP中,当你选择某一个功能时,它都会跳转到登录界面,然而登录界面都是一样的,所以我们完全可以将这个登录控制器设置成一个单例.这样可以节省内存的开销,优化我们的内存,下面纯属个人整理,如果有错误,希望大家指出来,相互进步.下面我们正式开始介绍单例

单例模式

在写代码之前,我们好好整理整理思路

引入单例

// 不要忘记需要导入头文件哦

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建对个对象
    WGStudent *student1 = [[WGStudent alloc] init];
    WGStudent *student2 = [[WGStudent alloc] init];
    WGStudent *student3 = [[WGStudent alloc] init];
    WGStudent *student4 = [[WGStudent alloc] init];
    WGStudent *student5 = [[WGStudent alloc] init];

    // 打印对应的地址
    NSLog(@"S1=%p,S2=%p,S3=%p,S4=%p,S5=%p",student1,student2,student3,student4,student5);
}

打印结果

S1=0x7ff4fae07a30
S2=0x7ff4fae0e520
S3=0x7ff4fae04580
S4=0x7ff4fae0e390
S5=0x7ff4fae0e430

单例模式的原理

创建单例的格式

GCD方式 : dispatch_once_t
步骤 :

dispatch_once_t实现单例代码

在WGStudent.h文件中
#import <Foundation/Foundation.h>

@interface WGStudent : NSObject

/**
 *  声明一个类方法,表明自己是一个单例
 */
+ (instancetype)shareInstance;

@end

在WGStudent.m文件中
#import "WGStudent.h"

// 协议可以不遵守吗? (我没有删掉是因为便于理解代码)
@interface WGStudent() <NSCopying, NSMutableCopying>

@end

// onceToken的主要作用是什么?
@implementation WGStudent

// 为什么要定义一个static全局变量?
static WGStudent *_instance;

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    // 这里使用dispatch_once_t的目的是什么?
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        _instance = [super allocWithZone:zone];

    });

    return _instance;
}

+ (instancetype)shareInstance
{
    // 这里使用dispatch_once_t的目的是什么?
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        _instance = [[self alloc] init];
    });

    return _instance;
}

// 重写下面两个对象方法的注意点是什么
- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

@end

打印结果

S1=0x7faceb53b2c0
S2=0x7faceb53b2c0
S3=0x7faceb53b2c0
S4=0x7faceb53b2c0
S5=0x7faceb53b2c0

普通方式if来创建单例

首先我们来写一份不够严谨的代码,看看问题出来哪里


#import "WGStudent.h"

@interface WGStudent() <NSCopying, NSMutableCopying>

@end

@implementation WGStudent

// 定义全局变量,保证整个进程运行过程中都不会释放
static WGStudent *_instance;

// 保证整个进程运行过程中,只会分配一个内存空间

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    if (nil == _instance) {
        _instance = [super allocWithZone:zone];
    }
    return _instance;
}

+ (instancetype)shareInstance
{
    if (nil == _instance) {
        _instance = [[self alloc] init];
    }
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

@end

打印结果

S1=0x7febf153ba80
S2=0x7febf153ba80
S3=0x7febf153ba80
S4=0x7febf153ba80
S5=0x7febf153ba80

解决后的代码

#import "WGStudent.h"

@interface WGStudent()

@end

@implementation WGStudent

// 定义全局变量,保证整个进程运行过程中都不会释放
static WGStudent *_instance;

// 保证整个进程运行过程中,只会分配一个内存空间

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (nil == _instance) {
            _instance = [super allocWithZone:zone];
        }
        return _instance;
    }
}

+ (instancetype)shareInstance
{
    @synchronized(self) {

        if (nil == _instance) {
            _instance = [[self alloc] init];
        }
        return _instance;
    }

}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}
@end

打印结果

S1=0x7fd39af539d0
S2=0x7fd39af539d0
S3=0x7fd39af539d0
S4=0x7fd39af539d0
S5=0x7fd39af539d0

以上就是实现在ARC环境下创建单例的两种方法

接下来我们来创建MRC环境下的单例

设置环境.png

下面是MRC环境下的代码

在.h文件中声明单例方法
#import <Foundation/Foundation.h>

@interface WGStudent : NSObject

/**
 *  声明一个类方法,表明自己是一个单例
 */
+ (instancetype)shareInstance;

@end
在.m文件中重写方法

#import "WGStudent.h"

@interface WGStudent()

@end

@implementation WGStudent

#pragma mark - ARC环境下的单例
// 定义全局变量,保证整个进程运行过程中都不会释放
static WGStudent *_instance;

// 保证整个进程运行过程中,只会分配一个内存空间

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (nil == _instance) {
            _instance = [super allocWithZone:zone];
        }
        return _instance;
    }
}

+ (instancetype)shareInstance
{
    @synchronized(self) {

        if (nil == _instance) {
            _instance = [[self alloc] init];
        }
        return _instance;
    }

}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

#pragma mark - MRC环境下的单例(还要加上上面的方法)

#if __has_feature(objc_arc)
// ARC :就执行上面重写的方法即可
#else
// MRC : 除了执行上面的方法,还需要重写下面的方法.

- (oneway void)release {

    // 什么都不用做,安静的看着其他方法装逼即可
}

- (instancetype)retain
{
    return _instance;
}

- (NSUInteger)retainCount
{
    return MAXFLOAT;
}
#endif

@end

打印结果

S1=0x7f9b6bd90fb0
S2=0x7f9b6bd90fb0
S3=0x7f9b6bd90fb0
S4=0x7f9b6bd90fb0
S5=0x7f9b6bd90fb0
- (void)currentEnvironment
{
#if __has_feature(objc_arc)
        //  ARC
        NSLog(@"ARC环境");
#else
        //  MRC
        NSLog(@"MRC环境");
#endif
}

以上就是ARC和MRC环境下的单例

单例宏代码

// 直接将单例的实现(ARC和MRC)全部定义到PCH文件中,,设置PCH文件路径即可
#define SingleH(instance) +(instancetype)share##instance;

#if __has_feature(objc_arc)
//ARC
#define SingleM(instance) static id _instance;\
\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
\
+(instancetype)share##instance\
{\
return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}
#else

//MRC
#define SingleM(instance) static id _instance;\
\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
\
+(instancetype)share##instance\
{\
return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{\
}\
-(instancetype)retain\
{\
    return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
    return MAXFLOAT;\
}
#endif

这里需要重点听 : 有的初学者朋友可能会使用继承,这样就不用把它定义成宏了,我上面就说过了,我们千万不能在单例中使用继承,原因我们看代码,不要耍流氓

使用继承

在.h文件中
#import <Foundation/Foundation.h>

@interface WGSignaltonTool : NSObject

/**
 *  声明一个类方法,表明自己是一个单例
 */
+ (instancetype)shareInstance;

@end


在.m文件中
#import "WGSignaltonTool.h"

@implementation WGSignaltonTool

#pragma mark - ARC环境下的单例
// 定义全局变量,保证整个进程运行过程中都不会释放
static WGSignaltonTool *_instance;

// 保证整个进程运行过程中,只会分配一个内存空间

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (nil == _instance) {
            _instance = [super allocWithZone:zone];
        }
        return _instance;
    }
}

+ (instancetype)shareInstance
{
    @synchronized(self) {

        if (nil == _instance) {
            _instance = [[self alloc] init];
        }
        return _instance;
    }

}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

#pragma mark - MRC环境下的单例(还要加上上面的方法)

#if __has_feature(objc_arc)
// ARC :就执行上面重写的方法即可
#else
// MRC : 除了执行上面的方法,还需要重写下面的方法.

- (oneway void)release {

    // 什么都不用做,安静的看着其他方法装逼即可
}

- (instancetype)retain
{
    return _instance;
}

- (NSUInteger)retainCount
{
    return MAXFLOAT;
}
#endif

@end

创建两个子类:WGPerson和WGStudent,分别继承WGSignaltonTool,两个子类只需要继承父类即可,什么都不用写

NSLog(@"%@,%@",[WGPerson shareInstance],[[WGPerson alloc] init]);

打印结果

<WGPerson: 0x7f9912d93b40>
<WGPerson: 0x7f9912d93b40>
NSLog(@"%@,%@",[WGStudent shareInstance],[[WGStudent alloc] init]);
NSLog(@"%@,%@",[WGPerson shareInstance],[[WGPerson alloc] init]);

打印结果

单例[1569:88929] <WGStudent: 0x7f9daa4032f0>,<WGStudent: 0x7f9daa4032f0>
单例[1569:88929] <WGStudent: 0x7f9daa4032f0>,<WGStudent: 0x7f9daa4032f0>

上一篇下一篇

猜你喜欢

热点阅读