• iOS中单例模式:MRC和ARC+GCD实现


      iOS中单例模式的实现一般分为两种:MRC和ARC+GCD

      1.MRC(非ARC)

      非ARC的单例的实现方式:

    #import <Foundation/Foundation.h>
    @interface NoARCSingleton:NSObject
    //这个属性在后面调试有用处,而且也不要苦恼为什么是retain?不应该是copy么?请继续看下去,后面自然明白了
    @property (nonatomic,retain) NSString *tempProperty; +(NoARCSingleton *)sharedInstance; @end @implementation NoARCSingleton static NoARCSingleton *sharedInstance = nil; //获取一个单例对象 + (BVNonARCSingleton *)sharedInstance {
    //--------------------------------------------------
    if (sharedInstance == nil) { sharedInstance = [[super allocWithZone:NULL] init]; } return sharedInstance;
    //-------------------------------------------------- } //当第一次使用这个单例的时候,会调用这个init方法。 -(id)init { self = [super init]; if(self){ //通常在这里做一些相关的初始化任务 return self; } } //这个delloc方法永远都不会被调用,因为在程序的生命周期内,该单例都必须存在,该方法可以不用实现 -(void)delloc { [super dealloc]; } //通过返回当前的单例对象的方式来防止实例化新的对象 + (id)allocWithZone:(NSZone*)zone {
      //线程相关的操作安全有
    sharedInstance处理
    return [[self sharedInstance] retain]; } 
    //同样的,不希望生成单例的多个拷贝,必须重写
    - (id)copyWithZone:(NSZone *)zone { return self; }
    //这个方法中什么操作都不需要该单例并不需要一个引用计数(retain counter)
    -(id)retain { return self; }
    //替换掉引用计数器,这样永远都不会release这个单例了
    - (NSUInteger)retainCount { return NSUIntegerMax; }
    // 该方法是空的——不希望用户release掉这个对象。
    -(oneway void)release{ }
    //除了返回单例外,什么也不做。
    -(id)autorelease { return self; }
    @end
    //@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。 一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。
    //非ARC实现单例的方法是线程不安全的,如果有多个线程同时调用sharedInstance方法获取一个实例,而sharedInstance需要花费1-2s的时间,那么NonARCSingleton的init方法可能会被多次的调用,也就是多个线程获得的单例有可能不是一个单例,解决这个线程不安全的方式是使用@synchronized来创建互斥锁即可。
    //当然,该方法不能保证该单例中所有方法的调用都是线程安全的
    //所以上面的横线之间的代码应该换成下面的代码 @synchronized (self)
    { if(sharedInstance == nil) { sharedInstance = [[super allocWithZone:NULL] init]; }
    #param mark -提醒:在iOS中,一般不建议使用非ARC来实现单例模式。更好的方法是使用ARC+GCD来实现。

      ARC实现的方式

    #import "ARCSingleton.h"
    @interface ARCSingleton : NSObject
    //调试之用和上面的代码作用类似的,这里为什么用weak呢?请继续看下去~
    @property  ( nonatomic, weak) NSString  *tempProperty; + (ARCSingleton *)sharedInstance; @end @implementation ARCSingleton + (ARCSingleton *) sharedInstance {
    static ARCSingleton *sharedInstance = nil ;
         static  dispatch_once_t onceToken = 0;  // 锁
         dispatch_once (&onceToken, ^ {     // 最多调用一次
           sharedInstance = [[self  alloc] init];
        });
        return  sharedInstance;
    }
    //当第一次使用这个单例时,会调用这个init方法
    -(id)init
    {
        self = [super init];
        if(self){
           //初始化单例
        }   
        return self;   
    }
    @end
    
    //在上面的代码中,调用Grand Central Dispatch 
    (GCD)
    中的dispatch_once方法就可以确保ARCSingleton只被实例化一次。并且该方法是线程安全的,我们不用担心在不同的线程中,会获得不同的实例。(当然,该方法同样不能保证该单例中所有方法的调用都是线程安全的)。

      当然在ARC中,不用GCD也是可以做到线程安全的,跟之前非ARC代码中使用@synchronized一样,如下代码:

     // 不使用GCD,通过@synchronized
    @synchronized (self)
    {    
    if(sharedInstance == nil)
        {
            sharedInstance = [[self alloc] init];
        }
    }
    

      为了简化使用ARC+GCD来创建单例,可以使用下面这个宏

    #define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) 
    
    static dispatch_once_t onceToken = 0; 
    
     static id sharedInstance = nil; 
    
    dispatch_once(&onceToken, ^{ 
    
    sharedInstance = block(); }); 
    
    return sharedInstance; 
    //如果对于macro有问题的话强烈建议去脑补下猫神的文章http://onevcat.com/2014/01/black-magic-in-macro/
    //另外猫神的很多文章都是很深入的建议有时间多去细细品味

      宏写完了之后那就so easy了!

      实例化方法实现:

    + (BVARCSingleton *) sharedInstance
    {    
    DEFINE_SHARED_INSTANCE_USING_BLOCK(^{
           return [[self alloc] init];
        });
    }
    //Done

      单例的使用:单例的使用方法很简单,在代码中的任意位置,如下使用即可:

        在BVAppDelegate.m中添加头文件:
      #import "NonARCSingleton.h"
      #import "ARCSingleton.h"

    - (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
       
      [NonARCSingleton sharedInstance].tempProperty = @"非ARC单例的实现";
        
      NSLog(@"%@", [BVNonARCSingleton sharedInstance].tempProperty);
    
        
      [ARCSingleton sharedInstance].tempProperty = @"ARC单例的实现";
        
      NSLog(@"%@", [ARCSingleton sharedInstance].tempProperty);
         
      return YES;
    }
    

       附加干货

      __weak,__strong

      很少会见到 __weak 和 __strong 出现在声明中,但我们需要对它们有一定的了解。 
    默认情况下,一个指针都会使用 __strong 属性,表明这是一个强引用。这意味着,只要引用存在,对象就不能被销毁。这是一种所期望的行为:当所有(强)引用都去除时,对象才能被收集和释放。不过, 有时我们却希望禁用这种行为:一些集合类不应该增加其元素的引用,因为这会引起对象无法释放。在这种情况下,我们需要使用弱引用(不用担心,内置的集合类 就是这么干的),使用 __weak 关键字。NSHashTable 就是一个例子。当被引用的对象消失时,弱引用会自动设置为 nil。Cocoa 的 nsnotificationcenter 就是这么一个例子,虽然这已经超出纯 Objective-C 的语言范畴 .

  • 相关阅读:
    AJAX 基础知识
    jQuery知识点总结
    css基础应用总结
    javascript 总结
    找回密码-博客园
    centerOS 7 安装MySql
    java leetcode TreeNode类、ListNode类的实现
    iOS StatusBar状态栏文字颜色更改
    使用Jmeter压力测试工具测试
    安装node.js
  • 原文地址:https://www.cnblogs.com/azxfire/p/3778851.html
Copyright © 2020-2023  润新知