zoukankan      html  css  js  c++  java
  • 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 的语言范畴 .

  • 相关阅读:
    【leetcode】1020. Partition Array Into Three Parts With Equal Sum
    【leetcode】572. Subtree of Another Tree
    【leetcode】123. Best Time to Buy and Sell Stock III
    【leetcode】309. Best Time to Buy and Sell Stock with Cooldown
    【leetcode】714. Best Time to Buy and Sell Stock with Transaction Fee
    【leetcode】467. Unique Substrings in Wraparound String
    【leetcode】823. Binary Trees With Factors
    【leetcode】143. Reorder List
    【leetcode】1014. Capacity To Ship Packages Within D Days
    【leetcode】1013. Pairs of Songs With Total Durations Divisible by 60
  • 原文地址:https://www.cnblogs.com/azxfire/p/3778851.html
Copyright © 2011-2022 走看看