iOS单例的创建与销毁

作者: laughingkid | 来源:发表于2016-01-06 21:01 被阅读11555次

    c#iOS单例的创建与销毁

    单例:单例模式使一个类只有一个实例.单例是在使用过程,保证全局有唯一的一个实例.这样,才能满足统一管理的功能.例如,一个数据库,只需要全局统一的读取,写入操作.不要多个实例去读写.d单例是唯一实例,它不等同于一直伴随这app的生命周期.下面,我会从单例的创建与销毁去分析单例.

    单例的创建

    单例的创建分为arcmrc,两种模式下的创建.

    • ARC 下的创建
      1. 先定义一个静态的instance. static MyClass _instance;
      2. 重写allocWithZone方法.此方法为对象分配空间必须调用方法.
      3. 定一个个share的类方法.能够被全局调用的.此方法里需要考虑线程安全问题
      4. 如果需要copy,需要遵守NSCopying协议,以及在copyWithZone中,直接返回self;

    例子

    
    static Myclass _instance;
    方法一:
    +(id)shareInstance{ 
         @synchronized(self){
           if(_instance == nil)
                _instance = [MyClass alloc] init]; 
         }
         return _instance;
    }
    
    
    方法二:
    +(id)shareInstance{
         static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
          if(_instance == nil)
                _instance = [MyClass alloc] init]; 
        });
         return _instance;
    }
    以上两种方法都是线程安全的.不过苹果官方现在提倡方法二.
    
    
    This method exists for historical reasons; memory zones are no longer used by Objective-C. You should not override this method.
    
    //重写allocWithZone,里面实现跟方法一,方法二一致就行.
    +(id)allocWithZone:(struct _NSZone *)zone{
        static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
          if(_instance == nil)
                _instance = [MyClass alloc] init]; 
        });
         return _instance;
    } 这个函数重写,是错误的。请读者注意。
    
    //保证copy时相同
    -(id)copyWithZone:(NSZone *)zone{  
        return _instance;  
    } 
    
    

    这样就是一个完整的单例,保证怎么创建都是唯一的.

    • MRC下的创建 创建过程跟ARC下步骤一样.不过要处理一些内存管理的函数.
    //不需要计数器+1  
    - (id)retain {  
        return self;  
    }  
      
    //不需要. 堆区的对象才需要  
    - (id)autorelease {  
        return self;  
    }  
      
    //不需要  
    - (oneway void)release {  
    }  
      
    //不需要计数器个数. 直接返回最大无符号整数  
    - (NSUInteger)retainCount {  
        return UINT_MAX;  //参照常量区字符串的retainCount  
    }
    

    这样就能保证这个单例不会被无意释放.

    单例的销毁

    前面讲了单例的创建,但是有个别情况需要销毁单例.
    下面分别从两种创建方法对应两种销毁形式.

    方法一:
    +(void)attemptDealloc{
        [_instance release]; //mrc 需要释放,当然你就不能重写release的方法了.
        _instance = nil;
    }
    
    
    方法二:
    1. 必须把static dispatch_once_t onceToken; 这个拿到函数体外,成为全局的.
    2.
    +(void)attempDealloc{
        onceToken = 0; // 只有置成0,GCD才会认为它从未执行过.它默认为0.这样才能保证下次再次调用shareInstance的时候,再次创建对象.
        [_instance release];
        _instance = nil;
     }
    

    以上两种方法即为销毁单例的方法.

    相关文章

      网友评论

      • 张云龙:在单例销毁的时候你这里说要把onceToken拿到外面成为全局的,这样可以把onceToken置为0,这里有问个问题,+(id)shareInstance;和+(id)allocWithZone:(struct _NSZone *)zone;方法中都有onceToken,两个方法内是否应该使用不同的onceToken,比如onceToken1和onceToken2,销毁的时候分别置0,若使用同一个onceToken两个方法只会调用一个一次,可能无法创建单例。
        laughingkid:@张云龙 是在init之前会调用。
        张云龙:@laughingkid [MyClass alloc] init]方法执行后会调用allocWithZone吧?如果使用一个onceToken allocWithZone里面的[super allocWithZone]不会调用了,因为onceToken已经不是0了,你这里的allocWithZone李米娜应该执行[super allocWithZone]吧?
        laughingkid:@张云龙 不用,这个是全局变量,一个初始化了,另一个就不会走了,直接返回了
      • laughingkid:可以,
        -(void)attempDealloc{
        _instance = nil;
        }

        即可
        ttdiOS:@laughingkid 为什么我的销废后,打印还是有值》??第二次运行就没有值打印为nil
      • 云逸枫林:ARC下可以手动销毁么
      • 马铃薯蜀黍:不好意思我刚刚学习这一部分,问一个小问题。。。就是下面这个方法重写以后引用计数不是变成最大了吗?。。。那一次release 怎么能销毁呢。。。不是引用计数是0的时候才会销毁的么?。。。不知道怎么理解了,,,

        - (NSUInteger)retainCount {
        return UINT_MAX; //参照常量区字符串的retainCount
        }
        laughingkid:@马铃薯蜀黍 是的,单利不销毁的情况就是这样的
      • xclidongbo:你这种单例销毁方法对吗?怎么返回值为id类型呢? 而且实现中没有写return.
        xclidongbo:@laughingkid 赶紧改改。
        laughingkid:@xclidongbo 确实不应该有返回值,写的时候笔误

      本文标题:iOS单例的创建与销毁

      本文链接:https://www.haomeiwen.com/subject/cqtfkttx.html