iOS工作记录9:项目单例(直接拉用)

我就直接用个例子记录:

工程代码记录下来:

//

//  Ticket.h

#import <Foundation/Foundation.h>


@interface Ticket : NSObject


// 实例化票据的单例

+ (Ticket *)sharedTicket;


// 在多线程应用中,所有被抢夺资源的属性需要设置为原子属性

// 系统会在多线程抢夺时,保证该属性有且仅有一个线程能够访问

// 注意:使用atomic属性,会降低系统性能,在开发多线程应用时,尽量不要资源

// 另外,atomic属性,必须与@synchronized(同步锁)一起使用


// 票数

@property (assign, atomic) NSInteger tickets;


@end


//

//  Ticket.m


/**

 实现单例模型需要做三件事情

 1. 使用全局静态变量记录住第一个被实例化的对象

    static Ticket *SharedInstance

 2. 重写allocWithZone方法,并使用dispatch_once_t,从而保证在多线程情况下,

    同样只能实例化一个对象副本

 3. 建立一个以shared开头的类方法实例化单例对象,便于其他类调用,同时不容易引起歧义

    同样用dispatch_once_t确保只有一个副本被建立。


 另外关于被抢夺资源使用的注意事项

 在多线程应用中,所有被抢夺资源的属性需要设置为原子属性

 系统会在多线程抢夺时,保证该属性有且仅有一个线程能够访问

  注意:使用atomic属性,会降低系统性能,在开发多线程应用时,尽量不要资源

 另外,atomic属性,必须与@synchronized(同步锁)一起使用

 

 */



#import "Ticket.h"

static Ticket *SharedInstance;//使用全局静态变量记录住第一个被实例化的对象

@implementation Ticket

// 使用内存地址实例化对象,所有实例化方法,最终都会调用此方法

// 要实例化出来唯一的对象,需要一个变量记录住第一个实例化出来的对象

+ (id)allocWithZone:(NSZone *)zone

{

    // 解决多线程中,同样只能实例化出一个对象副本

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        SharedInstance = [super allocWithZone:zone];

    });


    return SharedInstance;

}


// 建立一个单例对象,便于其他类调用

+ (Ticket *)sharedTicket

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        SharedInstance = [[Ticket alloc]init];

    });

    

    return SharedInstance;

}


@end


//

//  MainViewController.m文件


//


#import "MainViewController.h"

#import "Ticket.h"



- (void)viewDidLoad

{

    [super viewDidLoad];


    [Ticket sharedTicket].tickets = 30;//单例使用

    

 

}



//=============================================重新介绍以下什么是单例模式================================

IOS 单例模式

 (2012-05-31 20:17:53)
单例模式顾名思义就是只有一个实例,它确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。它经常用来做应用程序级别的共享资源控制。这个模式使用频率非常高,通过一个单例类,可以实现在不同窗口之间传递数据。

在objective-c中要实现一个单例类,至少需要做以下四个步骤:

1、为单例对象实现一个静态实例,并初始化,然后设置成nil,
2、实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例,
3、重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实例的时候不产生一个新实例,
4、适当实现allocWitheZone,copyWithZone,release和autorelease


例子:为RootViewController创建一个单例函数:

static RootViewController *shareRootViewController = nil;
+(RootViewController *)sharedController{
        @synchronized(self){
                if(shareRootViewController == nil){
                        shareRootViewController = [[[self alloc] init] autorelease];
                }
        }
        return shareRootViewController;
}


+(id)allocWithZone:(NSZone *)zone{
        @synchronized(self){
                if (shareRootViewController == nil) {
                   shareRootViewController = [super allocWithZone:zone];
                    return  shareRootViewController;
                }
            }
        return nil;
}


NSZone: 简单来说可以把它想象成一个内存池,alloc或者dealloc这些操作都是在这个内存池中操作的,cocoa总是会分配一个默认的nsZone,任何 默认内存操作都是在这个zone上进行的,使用默认zone存在缺陷,因为他是全局范围的,频繁使用会导致内存的碎片化,尤其是大量的alloc和 dealloc的时候,性能上会受到一定影响。因为你完全可以自己生成一个zone并将alloc,copy这些限制在这个zone中。


iOS 创建单例的两种方法

创建一个单例很多办法。我先列举一个苹果官方文档中的写法。

  1. static AccountManager *DefaultManager = nil;  
  2.    
  3. + (AccountManager *)defaultManager {  
  4.     if (!DefaultManager) DefaultManager = [[self allocWithZone:NULL] init];  
  5.     return DefaultManager;  
  6. }  

当然,在iOS4之后有了另外一种写法:

  1. + (AccountManager *)sharedManager  
  2. {  
  3.         static AccountManager *sharedAccountManagerInstance = nil;  
  4.         static dispatch_once_t predicate;  
  5.         dispatch_once(&predicate, ^{  
  6.                 sharedAccountManagerInstance = [[self alloc] init];   
  7.         });  
  8.     return sharedAccountManagerInstance;  
  9. }  

该写法来自 objcolumnist,文中提到,该写法具有以下几个特性:

1. 线程安全。

2. 满足静态分析器的要求。

3. 兼容了ARC

然后我还有点好奇的是dispatch_once,这个函数,没见过啊。

于是就到官方的文档里找找看,是怎么说的。

下面是官方文档介绍:

 该方法的作用就是执行且在整个程序的声明周期中,仅执行一次某一个block对象。简直就是为单例而生的嘛。而且,有些我们需要在程序开头初始化的动作,如果为了保证其,仅执行一次,也可以放到这个dispatch_once来执行。

然后我们看到它需要一个断言来确定这个代码块是否执行,这个断言的指针要保存起来,相对于第一种方法而言,还需要多保存一个指针。

 方法简介中就说的很清楚了:对于在应用中创建一个初始化一个全局的数据对象(单例模式),这个函数很有用。

如果同时在多线程中调用它,这个函数将等待同步等待,直至该block调用结束。

这个断言的指针必须要全局化的保存,或者放在静态区内。使用存放在自动分配区域或者动态区域的断言,dispatch_once执行的结果是不可预知的。

总结:1.这个方法可以在创建单例或者某些初始化动作时使用,以保证其唯一性。2.该方法是线程安全的,所以请放心大胆的在子线程中使用。(前提是你的dispatch_once_t *predicate对象必须是全局或者静态对象。这一点很重要,如果不能保证这一点,也就不能保证该方法只会被执行一次。)


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。