iOS设计模式 ——单例模式详解以及严格单例模式注意点
2016-08-17 14:29
489 查看
一、我们常用的单例有哪些?
从这些常用的单例可以发现,通过这些常用的单例方法来获取到这个类的唯一实例,再在这个实例的基础上进行相关的操作、作业。
二、单例模式基本原理
单例模式,一般用来管理某些资源的,用来管理某个对象,他这个对象持有了某些核心资源,这个资源可以全局共享。大部分情况我们使用单例模式就是为了共享信息 ,一般作为管理中心。
缺点是因为他共享了信息,就破坏了设计模式中的最少知识原则,产生了耦合,破坏了封装性,。但是在解决问题的过程中,这种不好的地方也是可以忽略的。
下面我们来自己写一个单例的例子,详细的讲一下对单例的理解。创建一个UserInfoManagerCenter的类
仿照系统的单例形式自己写这个类方法。
在UserInfoManagerCenter.m中实现这个方法
但是这种方法并不好,当多个地方调用这个方法时,会造成同时都进入到alloc init。
因此,使用第二种方法
当然还有第三种方法 --- initialize的作用,同一个类初始化时只会调用一次。
让我们来验证下,然后在AppDelegate里赋值
在ViewController的viewDidLoad里取出值查看结果
三种方法结果能打印出来,单例实现了资源共享
三、严格单例模式的注意点
下面来简单谈谈严格的单例模式,有三个问题可能需要注意一下:
1.如何防止继承;
2.如何确保实例对象只出现一个;
3.防止实例对象被释放掉;
第一个问题,防止继承
创建一个子类继承自UserInfoManagerCenter,调用managerCenter会直接崩溃,比较简单这里就不截图了
第二个问题,如何确保实例对象只出现一个。除了类方法之类还有init方法,只能重写他的init方法,来实现init方法失效
第三个,由于现在是项目是ARC开发的,是引用计数管理的。无法重载release,可以跳过这个问题。
当然严格的单例模式,只要注意避免类似情况发生,就可以不用过多考虑这些负担了。
[[UIApplication sharedApplication] statusBarStyle];//系统中的单例模式,通过它获取到状态栏的style
[NSNotificationCenter defaultCenter] addObserver:<#(nonnull id)#> selector:<#(nonnull SEL)#> name:<#(nullable NSString *)#> object:<#(nullable id)#>];//defaultCenter从控制中心类中获取到了单例的实例
[NSUserDefaults standardUserDefaults] setObject:<#(nullable id)#> forKey:<#(nonnull NSString *)#>];
[NSFileManager defaultManager];
从这些常用的单例可以发现,通过这些常用的单例方法来获取到这个类的唯一实例,再在这个实例的基础上进行相关的操作、作业。
二、单例模式基本原理
单例模式,一般用来管理某些资源的,用来管理某个对象,他这个对象持有了某些核心资源,这个资源可以全局共享。大部分情况我们使用单例模式就是为了共享信息 ,一般作为管理中心。
缺点是因为他共享了信息,就破坏了设计模式中的最少知识原则,产生了耦合,破坏了封装性,。但是在解决问题的过程中,这种不好的地方也是可以忽略的。
下面我们来自己写一个单例的例子,详细的讲一下对单例的理解。创建一个UserInfoManagerCenter的类
仿照系统的单例形式自己写这个类方法。
#import <Foundation/Foundation.h>
@interface UserInfoManagerCenter : NSObject
@property (nonatomic ,strong) NSString *name;
@property (nonatomic ,strong) NSString *age;
+ (instancetype)managerCenter;
@end
在UserInfoManagerCenter.m中实现这个方法
#import "UserInfoManagerCenter.h"
@implementation UserInfoManagerCenter
/**
* 常规做法
*/
+(instancetype)managerCenter
{
static UserInfoManagerCenter *center = nil;//静态变量持有这个对象
if (center == nil) {
center = [[UserInfoManagerCenter alloc]init];
}
return center;
}
@end
但是这种方法并不好,当多个地方调用这个方法时,会造成同时都进入到alloc init。
因此,使用第二种方法
#import "UserInfoManagerCenter.h"
@implementation UserInfoManagerCenter
/**
* 第二种方案,用dispatch_once来解决竞争问题
*/
+(instancetype)managerCenter
{
static UserInfoManagerCenter *center = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
center = [[UserInfoManagerCenter alloc]init];
});
return center;
}
@end
当然还有第三种方法 --- initialize的作用,同一个类初始化时只会调用一次。
#import "UserInfoManagerCenter.h"
static UserInfoManagerCenter *center = nil;
@implementation UserInfoManagerCenter
/**
* 第三种方法,每个类调用任意方法时都会提前调用的这个initialize方法,initialize的作用,同一个类初始化时只会调用一次。所以说我们将单例写在这个地方也是没有问题的,但是不推荐
*/
+(void)initialize
{
if (self == [UserInfoManagerCenter class]) {
center = [[UserInfoManagerCenter alloc]init];
}
}
+(instancetype)managerCenter
{
return center;
}
@end
让我们来验证下,然后在AppDelegate里赋值
#import "AppDelegate.h"
#import "UserInfoManagerCenter.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UserInfoManagerCenter *center = [UserInfoManagerCenter managerCenter];
center.name = @"YUSIR";
return YES;
}
在ViewController的viewDidLoad里取出值查看结果
#import "ViewController.h"
#import "UserInfoManagerCenter.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UserInfoManagerCenter * center = [UserInfoManagerCenter managerCenter];
NSLog(@"name:%@",center.name);
}
三种方法结果能打印出来,单例实现了资源共享
三、严格单例模式的注意点
下面来简单谈谈严格的单例模式,有三个问题可能需要注意一下:
1.如何防止继承;
2.如何确保实例对象只出现一个;
3.防止实例对象被释放掉;
第一个问题,防止继承
+(instancetype)managerCenter
{
static UserInfoManagerCenter *center = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
center = [[UserInfoManagerCenter alloc]init];
});
//防止子类重载调用使用
NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil); //填nil会导致程序崩溃
}
return center;
}
创建一个子类继承自UserInfoManagerCenter,调用managerCenter会直接崩溃,比较简单这里就不截图了
第二个问题,如何确保实例对象只出现一个。除了类方法之类还有init方法,只能重写他的init方法,来实现init方法失效
static UserInfoManagerCenter *center = nil;
@implementation UserInfoManagerCenter
+(instancetype)managerCenter
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
center = (UserInfoManagerCenter *)@"UserInfoManagerCenter";
center = [[UserInfoManagerCenter alloc]init];
});
//防止子类重载调用使用
NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil); //填nil会导致程序崩溃
}
return center;
}
- (instancetype)init {
NSString *string = (NSString *)center;
if ([string isKindOfClass:[NSString class]]== YES && [string isEqualToString:@"UserInfoManagerCenter"]) {
self = [super init];
if (self) {
//防止子类重载调用使用
NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
NSParameterAssert(nil); //填nil会导致程序崩溃
}
}
return self;
}else {
return nil;
}
}
第三个,由于现在是项目是ARC开发的,是引用计数管理的。无法重载release,可以跳过这个问题。
当然严格的单例模式,只要注意避免类似情况发生,就可以不用过多考虑这些负担了。
相关文章推荐
- iOS单例(设计模式)详解
- ios计算个税方法以及ui界面设计代码详解
- iOS中的单例设计模式详解
- iOS 开发 多线程详解之GCD应用延迟操作,单例设计模式,调度组
- 详解iOS App设计模式开发中对于享元模式的运用
- 设计模式之代理模式 c++实现以及详解
- IOS-34-单例设计模式详解
- iOS的Objective-C的工厂设计模式详解
- 手把手教学:详解Swift中的iOS设计模式
- iOS 设计模式详解Demo
- 设计模式之单例模式 c++实现以及详解
- IOS常用的设计模式以及对应的优势
- iOS单例设计模式详解教程
- 详解iOS应用开发中使用设计模式中的抽象工厂模式
- Ios中关于IB简介、视图、以及设计模式相关知识
- iOS中MVC等设计模式详解
- iOS开发设计模式详解
- 详解Swift中的iOS设计模式
- iOS巅峰之MVC(设计模式)详解
- 详解iOS应用的设计模式开发中Mediator中介者模式的使用