1.单利模式概述
链接: iOS开发懒汉模式&恶寒模式
2.使用GCD实现单利模式
2.1新建一个project,然后新建一个HMDataTool类展示GCD实现单例模式
#import <Foundation/Foundation.h>
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
@end
#import "HMDataTool.h"
@implementation HMDataTool
// 用来保存唯一的单例对象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ //onceToken是GCD用来记录是否执行过 ,如果已经执行过就不再执行(保证执行一次)
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
@end
#import "htingViewController.h"
#import"HMDataTool.h"
@interface htingViewController ()
@end
@implementation htingViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
HMDataTool *tool1 = [HMDataTool sharedDataTool];
HMDataTool *tool2 = [HMDataTool sharedDataTool];
HMDataTool *tool3 = [[HMDataTool alloc] init];
HMDataTool *tool4 = [[HMDataTool alloc] init];
NSLog(@"%@ %@ %@ %@", tool1, tool2, tool3, tool4);
}
@end
打印结果
使用GCD实现单利模式[2334:607] <HMDataTool: 0x8f064c0> <HMDataTool: 0x8f064c0> <HMDataTool: 0x8f064c0> <HMDataTool: 0x8f064c0>
3.非ARC实现单例模式
3.1非ARC内存管理模式下对象必须手动释放,为了防止那个唯一的单例对象被释放掉,则只需要重写下面的几个方法即可
- (oneway void)release { }
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1;}
- (id)autorelease { return self;}
3.2通过新建一个HMDataTool类来演示非ARC单例模式
// HMDataTool.h
#import <Foundation/Foundation.h>
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
@end
//
// HMDataTool.m
// 03-单例模式-Singleton(掌握)
//
// Created by apple on 14-9-16.
// Copyright (c) 2014年 heima. All rights reserved.
//
#import "HMDataTool.h"
@implementation HMDataTool
// 用来保存唯一的单例对象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
/**
* 重写下面几个关于引用计数器的方法就可以防止修改引用计数器的值,
这样就可以这个对象永远停留在内存中(因为这几个方法都是空的,所以尽管怎么调用,都没有作用)
*
* @return <#return value description#>
*/
- (oneway void)release { }
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1;}
- (id)autorelease { return self;}
@end
//
// HMViewController.h
#import <UIKit/UIKit.h>
@interface HMViewController : UIViewController
@end
//
// HMViewController.m
#import "HMViewController.h"
#import "HMDataTool.h"
@interface HMViewController ()
@end
@implementation HMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
HMDataTool *tool1 = [[HMDataTool alloc] init];
HMDataTool *tool2 = [[HMDataTool alloc] init];
HMDataTool *tool3 = [HMDataTool sharedDataTool];
HMDataTool *tool4 = [HMDataTool sharedDataTool];
/**
* 重写了下面几个方法之后,则随便释放N次都没有用了
- (oneway void)release { }
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1;}
- (id)autorelease { return self;}
*/
[tool4 autorelease];
[tool4 autorelease];
[tool4 autorelease];
[tool4 autorelease];
[tool4 autorelease];
NSLog(@"%@ %@ %@ %@", tool1, tool2, tool3, tool4);
}<pre name="code" class="objc">+(loginModel *)sharedloginModel
{
static loginModel *loginmodle = nil;
@synchronized(self)
{
if (loginmodle == nil) {
loginmodle = [[loginModel alloc] init];
}
}
return loginmodle;
}
@end 运行结果
单例模式-非ARC(掌握)[2592:607] <HMDataTool: 0x8d12600> <HMDataTool: 0x8d12600> <HMDataTool: 0x8d12600> <HMDataTool: 0x8d12600>
4.线程锁和GCD实现单例模式
4.1线程锁和GCD实现单粒模式
线程锁实现单粒
+(Muser *)sharedMuser
{
static *user = nil;
@synchronized(self)
{
if (user == nil) {
user = [[Muser alloc] init];
}
}
return user;
}
GCD实现单粒
+(<span style="font-family: Arial, Helvetica, sans-serif;">sharedsegMentTitles</span><span style="font-family: Arial, Helvetica, sans-serif;"> *</span><span style="font-family: Arial, Helvetica, sans-serif;">)sharedsegMentTitles</span>
{
static SwitchMenuViewModel * segTitles = nil;
static dispatch_once_t once;
dispatch_once(&once,^{
if (segTitles == nil) {
segTitles = [[SwitchMenuViewModel alloc]init];
}
});
return segTitles;
}
4.2为什么使用宏?
假设一个项目中有多个类需要单例,则需要每个类都实现一遍单例,这样很繁琐,因此可以采用定义宏的方式,写一个单例文件添加到项目中然后在项目的
Prefix.pch文件中得这个地方包含进去即可
// .h文件 shared##name 是让前面HMSingletonH(name) 接收到的参数拼接起来
#define HMSingletonH(name) + (instancetype)shared##name;
// .m文件 如果是ARC
#if __has_feature(objc_arc)
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
}
//如果是非ARC
#else
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
} \
\
- (oneway void)release { } \
- (id)retain { return self; } \
- (NSUInteger)retainCount { return 1;} \
- (id)autorelease { return self;}
#endif
//
// HMViewController.m
//
#import "HMViewController.h"
#import "HMMusicTool.h"
#import "HMMovieTool.h"
#import "HMDataTool.h"
#import "HMPerson.h"
@interface HMViewController ()
@end
@implementation HMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// HMMusicTool *tool1 = [HMMusicTool sharedMusicTool];
// HMMusicTool *tool2 = [HMMusicTool sharedMusicTool];
//
// HMMovieTool *tool3 = [HMMovieTool sharedMovieTool];
// HMMovieTool *tool4 = [HMMovieTool sharedMovieTool];
//
// HMDataTool *tool5 = [HMDataTool sharedDataTool];
// HMDataTool *tool6 = [HMDataTool sharedDataTool];
//
// NSLog(@"%@ %@", tool5, tool6);
HMPerson *p = [[HMPerson alloc] init];
#if __has_feature(objc_arc)
// 编译器是ARC环境
#else
// 编译器是MRC环境
[p release];
#endif
}
@end
为什么使用宏?
这样可以方便项目中的其它单例的创建,只需要在项目中包含即可共用,而不必要再次用代码为每一个单例对象实现单例