zoukankan      html  css  js  c++  java
  • iOS开发ARC与MRC下单例的完整写法与通用宏定义

    #import "XMGTool.h"
    /**
     *    1:ARC下的完整的单例写法:alloc内部会调用+(instancetype)allocWithZone:(struct _NSZone *)zone方法,所以重写该方法,用GCD一次性函数,默认是线程安全的加了一把锁,也可以自己去加锁
     @synchronized(self) {
     if (_instance == nil) {
     _instance = [super allocWithZone:zone];
     }
     }
     
     2:还要考虑copy和mutableCopy两种情况,要想重写两种方法,必须先遵守两个协议:<NSCopying, NSMutableCopying>协议,直接返回一个实例就可以,其中对象调用copy:无论可变不可变copy后的对象都是不可变的,若源对象不可变,则copy返回的是源对象,源对象引用计数加1,并copy了源对象的值,若源对象是可变的,则会产生一个新对象,新对象引用计数加1,mutableCopy,拷贝的对象都是可变的,也都是新对象,新对象引用计数加1,只要是产生了新对象就是深拷贝,没产生新对象,只拷贝了指针就是浅拷贝
     3:对象调用new方法创建对象,就相当于调用了alloc init方法创建的对象
     */
    @implementation XMGTool
    
    //0.提供全局变量
    static XMGTool *_instance;
    
    //1.alloc-->allocWithZone
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        //加互斥锁解决多线程访问安全问题
    //    @synchronized(self) {
    //        if (_instance == nil) {
    //            _instance = [super allocWithZone:zone];
    //        }
    //    }
        
        //本身就是线程安全的
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        
        return _instance;
    }
    
    //2.提供类方法
    +(instancetype)shareTool
    {
        return [[self alloc]init];
    }
    
    //3.严谨
    -(id)copyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    @end

    2:MRC

    #import "XMGTool.h"
    /**
     *    MRC下单例的实现:1:需要重写release方法,什么都不做,因为不需要release操作 2:retain会产生新对象操作会使引用计数加1,此时返回一个已经创建的实例,3:重写retainCount方法,返回一个最大值
     */
    @implementation XMGTool
    
    //修改环境为MRC
    //0.提供全局变量
    static XMGTool *_instance;
    
    //1.alloc-->allocWithZone
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        //加互斥锁解决多线程访问安全问题
    //    @synchronized(self) {
    //        if (_instance == nil) {
    //            _instance = [super allocWithZone:zone];
    //        }
    //    }
        
        //本身就是线程安全的
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        
        return _instance;
    }
    
    //2.提供类方法
    +(instancetype)shareTool
    {
        return [[self alloc]init];
    }
    
    //3.严谨
    -(id)copyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    #if __has_feature(objc_arc)
    //条件满足 ARC
    #else
    // MRC
    -(oneway void)release
    {
        
    }
    
    -(instancetype)retain
    {
        return _instance;
    }
    
    //习惯
    -(NSUInteger)retainCount
    {
        return MAXFLOAT;
    }
    
    #endif
    
    @end

    3:通用宏定义:

    #define SingleH(name) +(instancetype)share##name;
    
    #if __has_feature(objc_arc)
    //条件满足 ARC
    #define SingleM(name) static id _instance;
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    _instance = [super allocWithZone:zone];
    });
    
    return _instance;
    }
    
    +(instancetype)share##name
    {
    return [[self alloc]init];
    }
    
    -(id)copyWithZone:(NSZone *)zone
    {
    return _instance;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
    return _instance;
    }
    
    #else
    //MRC
    #define SingleM(name) static id _instance;
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    _instance = [super allocWithZone:zone];
    });
    
    return _instance;
    }
    
    +(instancetype)share##name
    {
    return [[self alloc]init];
    }
    
    -(id)copyWithZone:(NSZone *)zone
    {
    return _instance;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
    return _instance;
    }
    -(oneway void)release
    {
    }
    
    -(instancetype)retain
    {
        return _instance;
    }
    
    -(NSUInteger)retainCount
    {
        return MAXFLOAT;
    }
    #endif

    ```objc

    使用Crearte函数创建的并发队列和全局并发队列的主要区别:

    1.全局并发队列在整个应用程序中本身是默认存在的,并且对应有高优先级、默认优先级、低优先级和后台优先级一共四个并发队列,我们只是选择其中的一个直接拿来用。而Crearte函数是实打实的从头开始去创建一个队列。

    2.在iOS6.0之前,在GCD中凡是使用了带Create和retain的函数在最后都需要做一次release操作。而主队列和全局并发队列不需要我们手动release。当然了,在iOS6.0之后GCD已经被纳入到了ARC的内存管理范畴中,即便是使用retain或者create函数创建的对象也不再需要开发人员手动释放,我们像对待普通OC对象一样对待GCD就OK。

    3.在使用栅栏函数的时候,苹果官方明确规定栅栏函数只有在和使用create函数自己的创建的并发队列一起使用的时候才有效(没有给出具体原因)

    4.其它区别涉及到XNU内核的系统级线程编程,不一一列举。

    5.给出一些参考资料(可以自行研究):

    GCDAPI:https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_queue_create

    Libdispatch版本源码:http://www.opensource.apple.com/source/libdispatch/libdispatch-187.5/

    ```

    ###1.单例模式

    - 1.1 概念相关

    (1)单例模式

        在程序运行过程,一个类只有一个实例

    (2)使用场合

        在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

    - 1.2 ARC实现单例

    (1)步骤

        01 在类的内部提供一个static修饰的全局变量

        02 提供一个类方法,方便外界访问

        03 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间

        04 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法

    (2)相关代码

    ```objc

    //提供一个static修饰的全局变量,强引用着已经实例化的单例对象实例

    static XMGTools *_instance;

    //类方法,返回一个单例对象

    +(instancetype)shareTools

    {

         //注意:这里建议使用self,而不是直接使用类名Tools(考虑继承)

        return [[self alloc]init];

    }

    //保证永远只分配一次存储空间

    +(instancetype)allocWithZone:(struct _NSZone *)zone

    {

        //使用GCD中的一次性代码

    //    static dispatch_once_t onceToken;

    //    dispatch_once(&onceToken, ^{

    //        _instance = [super allocWithZone:zone];

    //    });

        //使用加锁的方式,保证只分配一次存储空间

        @synchronized(self) {

            if (_instance == nil) {

                _instance = [super allocWithZone:zone];

            }

        }

        return _instance;

    }

    /*

    1. mutableCopy 创建一个新的可变对象,并初始化为原对象的值,新对象的引用计数为 1;

    2. copy 返回一个不可变对象。分两种情况:(1)若原对象是不可变对象,那么返回原对象,并将其引用计数加 1 ;(2)若原对象是可变对象,那么创建一个新的不可变对象,并初始化为原对象的值,新对象的引用计数为 1。

    */

    //让代码更加的严谨

    -(nonnull id)copyWithZone:(nullable NSZone *)zone

    {

    //    return [[self class] allocWithZone:zone];

        return _instance;

    }

    -(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone

    {

        return _instance;

    }

    ```

    - 1.3 MRC实现单例

    (1)实现步骤

        01 在类的内部提供一个static修饰的全局变量

        02 提供一个类方法,方便外界访问

        03 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间

        04 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法

        05 重写release方法

        06 重写retain方法

        07 建议在retainCount方法中返回一个最大值

    (2)配置MRC环境知识

        01 注意ARC不是垃圾回收机制,是编译器特性

        02 配置MRC环境:build setting ->搜索automatic ref->修改为NO

    (3)相关代码

    ```objc

    //提供一个static修饰的全局变量,强引用着已经实例化的单例对象实例

    static XMGTools *_instance;

    //类方法,返回一个单例对象

    +(instancetype)shareTools

    {

         //注意:这里建议使用self,而不是直接使用类名Tools(考虑继承)

        return [[self alloc]init];

    }

    //保证永远只分配一次存储空间

    +(instancetype)allocWithZone:(struct _NSZone *)zone

    {

        //使用GCD中的一次性代码

    //    static dispatch_once_t onceToken;

    //    dispatch_once(&onceToken, ^{

    //        _instance = [super allocWithZone:zone];

    //    });

        //使用加锁的方式,保证只分配一次存储空间

        @synchronized(self) {

            if (_instance == nil) {

                _instance = [super allocWithZone:zone];

            }

        }

        return _instance;

    }

    //让代码更加的严谨

    -(nonnull id)copyWithZone:(nullable NSZone *)zone

    {

    //    return [[self class] allocWithZone:zone];

        return _instance;

    }

    -(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone

    {

        return _instance;

    }

    //在MRC环境下,如果用户retain了一次,那么直接返回instance变量,不对引用计数器+1

    //如果用户release了一次,那么什么都不做,因为单例模式在整个程序运行过程中都拥有且只有一份,程序退出之后被释放,所以不需要对引用计数器操作

    -(oneway void)release

    {

    }

    -(instancetype)retain

    {

        return _instance;

    }

    //惯用法,有经验的程序员通过打印retainCount这个值可以猜到这是一个单例

    -(NSUInteger)retainCount

    {

        return MAXFLOAT;

    }

    ```

    - 1.4 通用版本

    (1)有意思的对话

        01 问:写一份单例代码在ARC和MRC环境下都适用?

        答:可以使用条件编译来判断当前项目环境是ARC还是MRC

        02 问:条件编译的代码呢,么么哒?

    ```objc

    //答:条件编译

    #if __has_feature(objc_arc)

    //如果是ARC,那么就执行这里的代码1

    #else

    //如果不是ARC,那么就执行代理的代码2

    #endif

    ```

        03 问:在项目里面往往需要实现很多的单例,比如下载、网络请求、音乐播放等等,弱弱的问一句单例可以用继承吗?

        答:单例是不可以用继承的,如果想一次写就,四处使用,那么推荐亲使用带参数的宏定义啦!

        04 问:宏定义怎么弄?

        答:这个嘛~~回头看一眼我的代码咯,亲。

    (2)使用带参数的宏完成通用版单例模式代码

        01 注意条件编译的代码不能包含在宏定义里面

        02 宏定义的代码只需要写一次就好,之后直接拖到项目中用就OK

  • 相关阅读:
    016 vue的组件通信
    015 vue组件中的数据
    014 vue的组件化开发
    013 vue的js中的高阶函数
    012 vue的v-model的使用
    011 vue的购书案例
    010 vue的过滤器的使用
    CF1519F
    CF1519E
    CF1517F
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5851486.html
Copyright © 2011-2022 走看看