写一个Person类,要保证无论什么情况下创建Person对象返回的都是同一个对象(单例设计模式
单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。
一个最好的办法就是,让类自身负责保存它的唯一实例。
这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
因为要保证类型对象的单一性,所以就要考虑Objective C在实例化对象时候的各种方式。
因为在Objective C中创建的各个类型都继承自NSObject类型,所以我们需要考虑
NSObject类型里实例化的方法,下面让我们展开来说。
在Objective C的实例化对象的方式主要有两种,分别如下:
obj = [NSObject new];
obj = [[NSObject alloc]init];
第一种方式,用new方法初始化其实是第二种方式的总和,当调用new方法时,其实是先调用了alloc方法进行isa(is a pointer)操作,创建指针,指向内存中的数据结构,紧接着调用了init方法对数据进行初始化。
第二种方式看起来就很明确了,先调用alloc创建指针指向内存中的数据结构,再调用init方法初始化数据。这里需要注意的是,init方法只是起到了初始化数据的作用,其实也可以自定义初始化方法,即完全可以自定义一个普通返回NSObject类型的方法来代替init方法,即init方法是可以随意被代替的。只不过NSObject类型中new方法默认会调用init方法而已,init方法可以看作是NSObject类型的默认构造函数。
所以综上所述,其实只有alloc方法是每次必须调用的方法,那么我们只要控制住alloc方法,对此方法进行覆盖就可以保证类型对象的单一性了。
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (Person *)getPerson;
+ (id)allocWithZone:(NSZone *)zone;
- (id)copyWithZone:(NSZone *)zone;
- (id)retain;
- (NSUInteger)retainCount;
- (void)release;
- (id)autorelease;
@end
#import "Person.h"
@implementation Person
+ (Person *)getPerson
{
static Person *person = nil; // 静态的该类的实例
if(person == nil) // 只有为空的时候构建实例
{
person = [[super allocWithZone:NULL] init];
}
return person;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [[self getPerson] retain]; //返回单例
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (NSUInteger)retainCount
{
return NSUIntegerMax;
}
- (void)release
{}
- (id)autorelease
{
return self;
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p1 = [Person alloc];
Person *p2 = [Person getPerson];
Person *p3 = [Person alloc];
NSLog(@"\n\n%@\n%@\n%@\n", p1, p2, p3);
}
return 0;
}
执行后打印出来的三个实例的地址是一样的:
p1, p2, p3
说明它们是同一个实例,无论是 alloc 还是 getPerson.
1. 每一次 alloc 都得经过 allocWithZone: 方法,然后进到 getPerson方法,这就统一了入口
2. release/autorelease/retainCount 方法保证了实例不被释放
3. copyWithZone: 和 retain 用以确保克隆还是保留的仍然是原来那个唯一的实例