单例模式

UML类图:



实例实现代码:

@interface Singleton : NSObject

+ (Singleton *) sharedInstance;

@end


@implementation Singleton

static Singleton * sharedSingleton = nil;

+ (Singleton *) sharedInstance
{
    @synchronized(self)//--------1
    {
        if (sharedSingleton == nil) {
            sharedSingleton = [[super allocWithZone:NULL] init];//-----------2
        }
    }
    
    return sharedSingleton;
}

+ (id) allocWithZone:(struct _NSZone *)zone
{
    return [[self sharedInstance] retain];
}

- (id) copyWithZone:(NSZone *) zone//----------3
{
    return self;
}

- (id) retain
{
    return self;
}

- (NSUInteger) retainCount
{
    return NSUIntegerMax;//表示不能释放的对象
}


- (void) release
{
    //什么也不做
}

- (id) autorelease
{
    return self;
}

@end

说明:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。


1.多线程中多个线程同时调用sharedInstance方法的时候,会有可能创建多个实例,因此我们使用synchronized指令创建同步锁,使一个线程位于代码临界区时,另外一个线程等待。

2.使用super而不使用self是因为self已经重载了allocWithZone:方法,在allocWithZone:方法中,只是返回从sharedInstance方法返回的类实例,在Cocoa Touch框架中,调用类的allocWithZone:方法,会分配实例的内存,引用计数会置为1,然后会返回实例。我们已经见过alloc方法用于很多场合,其实,alloc是用设为NULL的zone来调用allocWithZone:,在默认区域(zone)为新实例分配内存。

3.重载copyWithZone:方法保证不会返回实例的新副本,而是返回self,同一个实例。

重载其他的方法保证他们什么都不做,只是返回self。


子类化Singleton:

首先我们定义一个子类

@interface SingletonSon : Singleton

@property (nonatomic,strong) NSString *name;

@end

@implementation SingletonSon

@end


客户端代码:

    Singleton *object = [Singleton sharedInstance];//---------1
    
    SingletonSon *objectSon = [[SingletonSon alloc]init];//-----------2

    NSLog(@"object.class = %s",object_getClassName(objectSon));
    
    if(objectSon == object)
    {
        NSLog(@"同一个实例");
    }
    
    objectSon.name = @"SingletonSon";

打印信息:

2015-05-06 15:40:21.380 AppTest[12228:115696] object.class = Singleton
2015-05-06 15:40:21.380 AppTest[12228:115696] 同一个实例
2015-05-06 15:40:21.380 AppTest[12228:115696] -[Singleton setName:]: unrecognized selector sent to instance 0x7fe7e35334d0


PS:

我们上面已经说过alloc是用设为NULL的zone来调用allocWithZone:,在默认区域(zone)为新实例分配内存

因此,当我们已经创建单例的实例以后,再创建子类的实例,会转发给super,调用super的allocWithZone:方法回到sharedInstance方法中去,因此最后无论怎么创建新的实例都是同一个实例,也就是说,如果我将1和2交换执行顺序,那么我的单例的实例类型就会是SingletonSon而不是Singleton,但是他们依然是同一个实例。


我们要如何子类化呢?

我们可以通过id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone)方法通过指定类的类型来实例化任何对象。

第一个参数是要实例化的类的类型;

第二个参数是用于索引的实例变量的额外的字节数,它总是0;

第三个参数用于指定内存中分配的区域,它一般为NULL,表示默认区域。


客户端代码:

    Singleton *object = [Singleton sharedInstance];//---------1
    
    SingletonSon *objectSon =[NSAllocateObject([SingletonSon class],0,NULL) init];//------------2

    NSLog(@"object.class = %s",object_getClassName(objectSon));
    
    if(objectSon == object)
    {
        NSLog(@"同一个实例");
    }
    
    objectSon.name = @"SingletonSon";


打印信息:

2015-05-06 15:42:17.483 AppTest[12319:116857] object.class = SingletonSon


PS:

此时无论1和2的顺序如何都不会是同一个实例变量了。


参考资料

-《大话设计模式》
-《Objective-C编程之道》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值