您的位置:首页 > 其它

单例的必要认识(深刻理解)

2017-12-20 16:02 246 查看


最近我面试人家,问他对单例的认识,他对单例的基本认识、创建方式回答全对,只有一点吞吞吐吐。

单例的认识

单例模式:单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例

系统单例:

1、UIApplication(应用程序实例)

2、NSNotificationCenter(消息中心):

3、NSFileManager(文件管理):

4、NSUserDefaults(应用程序设置):

5、NSURLCache(请求缓存):

6、NSHTTPCookieStorage(应用程序cookies池):

1.单例模式的要点:

  显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

2.单例模式的优点:

  1.安全性和唯一性:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例。单例类也可以防止他人复制(copy),保留(retain)或释放(release)实例。如果您发现需要,您可以创建自己的单例。例如,如果您有一个类为应用程序中的其他对象提供声音,则可以将其设为单例。

  2.灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

创建步骤

1、为你的单例类声明一个静态的实例(声明静态全局变量),并且初始化它的值为nil; eg:

static TestSingleton  *testSingleton = nil;


这样,在获取实例的方法中,只有在静态实例为nil的时候,产生一个你的类的实例,这个实例通常被称为共享的实例;

2、重写allocWithZone方法,用于确定:不能够使用其他的方法创建我们类的实例,限制用户只能通过获取实例的方法得到这个类的实例。所以我们在allocWithZone方法中直接返回共享的类实例;

3、写+(instancetype)shareSingleton的函数体

创建方法

一、传统方法

+(instancetype)shareSingleton{
static Singleton *singleton = nil;
if (singleton == nil){
singleton = [[self alloc] init];
}
return singleton;
}


二、推荐方法(GCD)

+(instancetype)shareSingleton{
static Singleton *singleton = nil;
//给单例加一个线程锁
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;```

三、线程加锁方法(不推荐使用)


+(instancetype)shareSingleton{

static Singleton *singleton = nil;

@synchronized(self) {

singleton = [[Singleton alloc] init];

}

return singleton;

}“`

注:“线程加锁方法”这样性能不是很好,因为每次调用+ (instancetype)sharedSingleton函数都会付出取锁的代价

吞吞吐吐:

但我问他,这样写的话是保证了线程安全,但通过自带的
alloc
或者
new
来进行实例化,还是不能保证该对象只被创建一次,如何避免呢?他就回答不上了,其实很简单:

.h头文件:

@interface TestSingleton : NSObject
@property (nonatomic, copy)NSString *testStr;
+ (TestSingleton *)shareinstance;

@end


.m文件:

+ (TestSingleton *)shareinstance {
static TestSingleton  *testSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//testSingleton = [self singletonAlloc]; //后面使用该创建方法
testSingleton = [self new];//[[self alloc]init];
});
return testSingleton;
}


//我们需要重载
alloc、new
方法

+ (instancetype)singletonAlloc
{
return [super alloc];
}

+ (instancetype)alloc
{
//加断言,使用alloc会蹦,并且reason提示
NSAssert(NO, @"不要用alloc,要使用singletonAlloc方法创建");
return nil;
}
+ (instancetype)new
{
return [self alloc];
}

+ (TestSingleton *)shareinstance {
static TestSingleton  *testSingleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
testSingleton = [[self singletonAlloc]init];
});
return testSingleton;
}


重载了alloc、allocWithZone和new方法,在alloc方法中加上断言来提醒,让用户不能使用alloc创建实例。

扩展一:(面试经常问到)



普通类允许调用者根据需要创建尽可能多的类的实例,而对于单例类,每个进程只能有一个类的实例,保证了单例数据的唯一性,安全性

调用下面方法:

-(void)testSigleton
{
/**
*  singleton和singleton2是同一个对象;
*/
TestSingleton *singleton = [TestSingleton shareinstance];
TestSingleton *singleton2 = [TestSingleton shareinstance];

if (singleton == singleton2) {
NSLog(@"singleton == singleton2");
}

NSLog(@"singleton地址:%@",singleton);
NSLog(@"singleton2地址:%@",singleton2);
}


打印如下

SingletonTest[1598:54880] singleton == singleton2
SingletonTest[1598:54880] singleton地址:<TestSingleton: 0x60000001e930>
SingletonTest[1598:54880] singleton2地址:<TestSingleton: 0x60000001e930>


可以看出地址一样,证明单例只会创建一个静态变量,全局唯一

扩展二:(宏定义单例)

作用:有时在项目中需要创建好多个单例,把单例的代码定义为宏,则可以省去重复代码,节省时间。

/**
*  在.h文件中定义的宏,arc
*
*  DWSingletonH(classname, accessorMethodName) 这个是宏
* 在外边我们使用 “DWSingletonH(classname,   accessorMethodName)” 那么在.h文件中,定义了一个方
法"+ (instancetype)accessorMethodName;"
*
*/
#define DWSingletonH(classname, accessorMethodName) + (instancetype)accessorMethodName;

/**
*  在.m文件中处理好的宏 arc
*
*  DWSingletonM(classname, accessorMethodName) 这个是宏,因为是多行的东西,所以每行后面都有一个"\",最后一行除外
*/
#define DWSingletonM(classname, accessorMethodName) \
static classname *instance_ = nil;\
+ (instancetype)accessorMethodName{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
instance_ = [[self alloc] init];\
});\
return instance_;\
}\
+ (instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
instance_ = [super allocWithZone:zone];\
});\
return instance_;\
}\
- (id)copyWithZone:(NSZone *)zone{\
return instance_;\
}


把上面代码用一个
Header File
文件里面,然后就可以在其他类快速创建单例了

* .h头文件:

@interface Singleton2 : NSObject
//@property double t;
DWSingletonH(Singleton2, shareInstance)
@end


.m文件:

@implementation Singleton2
DWSingletonM(Singleton2, shareInstance)
@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式 对象