zoukankan      html  css  js  c++  java
  • iOS多线程技术—单例模式(ARC)与(MRC)

    iOS多线程技术—单例模式(ARC)

    一、简单说明:

    设计模式:多年软件开发,总结出来的一套经验、方法和工具

    java中有23种设计模式,在ios中最常用的是单例模式和代理模式。

    二、单例模式说明

    (1)单例模式的作用 :可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源。

    (2)单例模式的使用场合:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),应该让这个类创建出来的对象永远只有一个。

    (3)单例模式在ARCMRC环境下的写法有所不同,需要编写2套不同的代码

    可以用宏判断是否为ARC环境

    #if __has_feature(objc_arc)
     // ARC
    #else
    // MRC
    #endif

    (4)在ARC中,单例模式的实现思路

    在.m中保留一个全局的static的实例   static id _instance; 

    1)重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)

    + (id)allocWithZone:(struct _NSZone *)zone
    {    @synchronized(self) {
            if (!_instance) {
                _instance = [super allocWithZone:zone];
            }
        }
        return _instance;
    }

    2)提供1个类方法让外界访问唯一的实例

    + (instancetype)sharedSoundTool
    {
        @synchronized(self) {
            if (!_instance) {
                _instance = [[self alloc] init];
            }
        }
        return _instance;
    }

    3)实现copyWithZone:方法

    + (id)copyWithZone:(struct _NSZone *)zone
     {
         return _instance;
     }

     (5)非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)

    实现内存管理方法

    - (id)retain { return self; }

    - (NSUInteger)retainCount { return 1; }

    - (oneway void)release {}

    - (id)autorelease { return self; }

      

    三、单例模式(ARC)

    1.说明

    重写allocWithzone:方法,控制内存分配。因为alloc内部会调用该方法,每次调用allocWithzone:方法,系统都会创建一块新的内存空间。

    alloc方法中:永远只分配一次内存

    init方法中:保证所有的MP3数据都只加载一次。

     2.代码示例

    创建一个音频工具类,继承子NSObject类。

    在该类中实现以下代码,观察:

     1 //
     2 //  YYAudioTool.m
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYAudioTool.h"
    10 @interface YYAudioTool ()
    11 //用来保存mp3文件
    12 @property(nonatomic,strong)NSMutableDictionary *muscis;
    13 @end
    14 @implementation YYAudioTool
    15 //构造方法
    16 -(id)init
    17 {
    18     if (self=[super init]) {
    19         //加载所需的音乐资源
    20         //....
    21 //        self.muscis=[NSMutableDictionary dictionary];
    22 //        self.muscis[@"1.mp3"]=1mp3数据;
    23 //        self.muscis[@"2.mp3"]=2mp3数据;
    24     }
    25     return self;
    26 }
    27 
    28 //两个方法的调用
    29 +(id)alloc
    30 {
    31     NSLog(@"alloc----");
    32     return [super alloc];
    33 }
    34 
    35 //控制内存分配,每次调用allocWithzone:方法,系统都会创建一块新的内存空间
    36 +(id)allocWithZone:(struct _NSZone *)zone
    37 {
    38     NSLog(@"allocWithZone---");
    39     return [super allocWithZone:zone];
    40 }
    41 
    42 
    43 
    44 @end
    View Code

    在主控制器中,创建工具类对象:

    打印结果:

    说明:在alloc内部会调用更底层的方法allocWithZone方法分配内存空间,上面的代码创建了四个不同的对象。 

    3.单例模式:设计思路 

    (1)永远只分配一块内存来创建对象

    (2)提供一个类方法,返回内部唯一的一个变量

    (3)最好保证init方法也只初始化一次

    代码示例:

    创建一个音频工具类,继承子NSObject类。

    在该类中按照设计思路实现以下代码:

    YYAudioTool.m文件

     1 //
     2 //  YYAudioTool.m
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYAudioTool.h"
    10 @interface YYAudioTool ()
    11 //用来保存mp3文件
    12 @property(nonatomic,strong)NSMutableDictionary *muscis;
    13 @end
    14 
    15 @implementation YYAudioTool
    16 //定义一份变量(整个程序运行过程中,只有一份)
    17 static id _instace;
    18 //单例模式:设计
    19 //(1)永远只分配一块内存来创建对象
    20 //(2)提供一个类方法,返回内部唯一的一个变量
    21 //(3)最好保证init方法也只初始化一次
    22 
    23 //构造方法
    24 -(id)init
    25 {
    26 //    __block id obj=nil;
    27     static id obj=nil;
    28     static dispatch_once_t onceToken;
    29     dispatch_once(&onceToken, ^{
    30         if ((obj=[super init]) != nil) {
    31             //加载所需的音乐资源
    32             //....
    33             //        self.muscis=[NSMutableDictionary dictionary];
    34             //        self.muscis[@"1.mp3"]=1mp3数据;
    35             //        self.muscis[@"2.mp3"]=2mp3数据;
    36         }
    37     });
    38     self=obj;
    39 
    40     return self;
    41 }
    42 
    43 
    44 //重写该方法,控制内存的分配,永远只分配一次存储空间
    45 +(id)allocWithZone:(struct _NSZone *)zone
    46 {
    47 
    48     //里面的代码只会执行一次
    49     static dispatch_once_t onceToken;
    50     dispatch_once(&onceToken, ^{
    51         _instace=[super allocWithZone:zone];
    52     });
    53     return _instace;
    54 }
    55 
    56 //类方法
    57 +(id)sharedAudioTool
    58 {
    59   //里面的代码永远都只执行一次
    60     static dispatch_once_t onceToken;
    61     dispatch_once(&onceToken, ^{
    62         _instace=[[self alloc]init];
    63     });
    64     return _instace;
    65 }
    66 
    67 +(id)copyWithZone:(struct _NSZone *)zone
    68 {
    69     return _instace;
    70 }
    71 @end
    View Code

    YYAudioTool.h文件

    1 #import <Foundation/Foundation.h>
    2 
    3 @interface YYAudioTool : NSObject
    4 //提供一个类方法,返回内部唯一的一个变量
    5 +(id)sharedAudioTool;
    6 @end

    主控制器中创建对象:

     1 //
     2 //  YYViewController.m
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYViewController.h"
    10 #import "YYAudioTool.h"
    11 
    12 @interface YYViewController ()
    13 
    14 @end
    15 
    16 @implementation YYViewController
    17 
    18 - (void)viewDidLoad
    19 {
    20     [super viewDidLoad];
    21 //    YYAudioTool *tool1=[[YYAudioTool alloc]init];
    22 //    YYAudioTool *tool2=[[YYAudioTool alloc]init];
    23     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
    24     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
    25     YYAudioTool *tool3=[[YYAudioTool alloc]init];
    26     YYAudioTool *tool4=[[YYAudioTool alloc]init];
    27     NSLog(@"%p--%p--%p--%p",tool1,tool2,tool3,tool4);
    28 }
    29 
    30 @end
    View Code

    观察打印结果:

     

    说明:整个程序中只创建一个对象实例。

    4.static补充:

    注意:static id instace=nil;和static id instace;instace=nil;的区别

     

     四、非ARC模式下的单例模式

    1.说明:把一个项目修改为非ARC的

    2.MAC下单例模式代码示例:

    新建一个工具类,让该类继承自NSObject。

    YYAudioTool.m文件

     1 //
     2 //  YYAudioTool.m
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYAudioTool.h"
    10 @interface YYAudioTool ()
    11 //用来保存mp3文件
    12 @property(nonatomic,strong)NSMutableDictionary *muscis;
    13 @end
    14 
    15 @implementation YYAudioTool
    16 //定义一份变量(整个程序运行过程中,只有一份)
    17 static id _instace;
    18 //单例模式:设计
    19 //(1)永远只分配一块内存来创建对象
    20 //(2)提供一个类方法,返回内部唯一的一个变量
    21 //(3)最好保证init方法也只初始化一次
    22 
    23 //构造方法
    24 -(id)init
    25 {
    26 //    __block id obj=nil;
    27     static id obj=nil;
    28     static dispatch_once_t onceToken;
    29     dispatch_once(&onceToken, ^{
    30         if ((obj=[super init]) != nil) {
    31     
    32         }
    33     });
    34     self=obj;
    35 
    36     return self;
    37 }
    38 
    39 
    40 //重写该方法,控制内存的分配,永远只分配一次存储空间
    41 +(id)allocWithZone:(struct _NSZone *)zone
    42 {
    43 
    44     //里面的代码只会执行一次
    45     static dispatch_once_t onceToken;
    46     dispatch_once(&onceToken, ^{
    47         _instace=[super allocWithZone:zone];
    48     });
    49     return _instace;
    50 }
    51 
    52 //类方法
    53 +(id)sharedAudioTool
    54 {
    55   //里面的代码永远都只执行一次
    56     static dispatch_once_t onceToken;
    57     dispatch_once(&onceToken, ^{
    58         _instace=[[self alloc]init];
    59     });
    60     return _instace;
    61 }
    62 
    63 //重写release方法
    64 //oneway :分布式对象
    65 -(oneway void)release
    66 {
    67 }
    68 
    69 //不管调用哪个方法,返回的都是唯一的实例,所以这里self和instace是一样的
    70 -(id)autorelease
    71 {
    72     return self;
    73 }
    74 
    75 -(id)retain
    76 {
    77     return self;
    78 }
    79 
    80 -(NSUInteger)retainCount
    81 {
    82     return 1;
    83 }
    84 
    85 +(id)copyWithZone:(struct _NSZone *)zone
    86 {
    87     return _instace;
    88 }
    89 @end
    View Code

    YYAudioTool.h文件

     1 //
     2 //  YYAudioTool.h
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface YYAudioTool : NSObject
    12 //提供一个类方法,返回内部唯一的一个变量
    13 +(id)sharedAudioTool;
    14 @end
    View Code

    主控制器中创建对象:

     1 //
     2 //  YYViewController.m
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYViewController.h"
    10 #import "YYAudioTool.h"
    11 
    12 @interface YYViewController ()
    13 
    14 @end
    15 
    16 @implementation YYViewController
    17 
    18 - (void)viewDidLoad
    19 {
    20     [super viewDidLoad];
    21     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
    22     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
    23     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
    24     YYAudioTool *tool4=[[YYAudioTool alloc]init];
    25     
    26     NSLog(@"%p--%p--%p--%p",tool1,tool2,tool3,tool4);
    27     
    28     //对象创建只会,release对象会销毁,无法再创建新的对象(因为单例),所以还需要重写release方法
    29     [tool1 release];
    30     [tool2 release];
    31     [tool3 release];
    32     [tool4 release];
    33 }
    34 
    35 @end
    View Code

    打印结果:

    说明:整个程序过程中,只创建一个对象实例。

     五、把单例代码定义为一个带参数的宏

    1.新的困扰

    弊端:如果又创建一个新的类,是否又要把文件代码拷贝一份,所以这里可以考虑把固定的代码写成宏。

    由于项目中代码经常有移植的需要,要求项目中又有ARC的,又有非ARC的,应该怎么应用单例模式?

    不管项目是ARC的还是非ARC的,这个宏都有用。可以先判断编译器的环境,判断当前环境是否是ARC的。

    条件编译的使用:

    2.使用条件编译,并把单例模式的代码定义为宏。

    新建一个.h头文件

      把代码定义为宏,头文件中的代码如下:

     1 // ## : 连接字符串和参数
     2 #define singleton_h(name) + (instancetype)shared##name;
     3 
     4 #if __has_feature(obj_arc)  //如果是ARC
     5 #define singleton_m(name) 
     6 static id _instance; 
     7 + (id)allocWithZone:(struct _NSZone *)zone 
     8 { 
     9     static dispatch_once_t onceToken; 
    10     dispatch_once(&onceToken, ^{ 
    11         _instance = [super allocWithZone:zone]; 
    12     }); 
    13     return _instance; 
    14 } 
    15 
    16 + (instancetype)shared##name 
    17 { 
    18     static dispatch_once_t onceToken; 
    19     dispatch_once(&onceToken, ^{ 
    20         _instance = [[self alloc] init]; 
    21     }); 
    22     return _instance; 
    23 } 
    24 
    25 + (id)copyWithZone:(struct _NSZone *)zone 
    26 { 
    27     return _instance; 
    28 }
    29 
    30 #else //非ARC
    31 #define singleton_m(name) 
    32 static id _instance; 
    33 + (id)allocWithZone:(struct _NSZone *)zone 
    34 { 
    35     static dispatch_once_t onceToken; 
    36     dispatch_once(&onceToken, ^{ 
    37         _instance = [super allocWithZone:zone]; 
    38     }); 
    39     return _instance; 
    40 } 
    41  
    42 + (instancetype)shared##name 
    43 { 
    44     static dispatch_once_t onceToken; 
    45     dispatch_once(&onceToken, ^{ 
    46         _instance = [[self alloc] init]; 
    47     }); 
    48     return _instance; 
    49 } 
    50  
    51 - (oneway void)release 
    52 { 
    53  
    54 } 
    55  
    56 - (id)autorelease 
    57 { 
    58     return _instance; 
    59 } 
    60  
    61 - (id)retain 
    62 { 
    63     return _instance; 
    64 } 
    65  
    66 - (NSUInteger)retainCount 
    67 { 
    68     return 1; 
    69 } 
    70  
    71 + (id)copyWithZone:(struct _NSZone *)zone 
    72 { 
    73     return _instance; 
    74 }
    75 #endif
    View Code

    在程序中的应用:

    控制器问价代码如下:

     1 #import "YYViewController.h"
     2 #import "YYAudioTool.h"
     3 
     4 @interface YYViewController ()
     5 
     6 @end
     7 
     8 @implementation YYViewController
     9 
    10 - (void)viewDidLoad
    11 {
    12     [super viewDidLoad];
    13     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
    14     
    15     //对象创建后,需要考虑
    16 //    (1)alloc init
    17 //    (2)release
    18 //    (3)copy copy内部会调用另外一个方法copywithzone
    19 //    (4)autorelease
    20 //    
    21     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
    22     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
    23     NSLog(@"%p---%p---%p",tool1,tool2,tool3);
    24     [tool2 release];
    25     [tool3 release];
    26     [tool1 release];
    27 
    28 }
    29 
    30 @end
    View Code

    工具类的头文件代码如下:

     1 #import "YYViewController.h"
     2 #import "YYAudioTool.h"
     3 
     4 @interface YYViewController ()
     5 
     6 @end
     7 
     8 @implementation YYViewController
     9 
    10 - (void)viewDidLoad
    11 {
    12     [super viewDidLoad];
    13     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
    14     
    15     //对象创建后,需要考虑
    16 //    (1)alloc init
    17 //    (2)release
    18 //    (3)copy copy内部会调用另外一个方法copywithzone
    19 //    (4)autorelease
    20 //    
    21     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
    22     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
    23     NSLog(@"%p---%p---%p",tool1,tool2,tool3);
    24     [tool2 release];
    25     [tool3 release];
    26     [tool1 release];
    27 
    28 }
    29 
    30 @end
    View Code

    工具类的实现部分代码如下:

     1 //
     2 //  YYAudioTool.h
     3 //  06-单例模式1
     4 //
     5 //  Created by apple on 14-6-25.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 #import "Singleton.h"
    11 
    12 @interface YYAudioTool : NSObject
    13 ////提供一个类方法,返回内部唯一的一个变量
    14 //+(id)sharedAudioTool;
    15 singleton_h(AudioTool)
    16 @end
    View Code

    补充说明:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。

    六、补充

    问题:ARC和非ARC单例模式的区别?

    由于非ARC是进行手动内存管理,所以需要注意下面一个方法,在项目中通常使用宏。

    - (id)retain { return self; }

    - (NSUInteger)retainCount { return 1; }

    - (oneway void)release {}

    - (id)autorelease { return self; }

  • 相关阅读:
    nodejs获取服务器数据到页面
    Struts 2
    JQuery
    JDBC
    Hiberbate
    EasyUi
    JavaScript
    利用 HashSet 去过滤元素是否重复
    HTML
    MySQL
  • 原文地址:https://www.cnblogs.com/asd5551680/p/4157395.html
Copyright © 2011-2022 走看看