Objective-C 中的单例

作者: 张嘉夫 | 来源:发表于2017-05-10 16:17 被阅读428次

    iOS 开发中我最常用的设计模式就是单例模式 。用于在代码间共享数据,极为有效,不需要手动传递数据。Cocoa Design Patterns 这本书写的非常好,里面有很多有关单例模式和其它模式的内容。


    后端

    单例类是需要重点理解的,它们展示出了一种非常实用的设计模式。整个 iOS SDK 都使用了这个设计模式,例如 UIApplication 有一个方法叫做 sharedApplication,可以在任意地方调用,会返回一个与当前运行应用相关的 UIApplication 实例。


    如何实现

    在 Objective-C 中,可以使用如下代码实现一个单例类:

    MyManager.h

    #import <foundation/Foundation.h>
    
    @interface MyManager : NSObject {
        NSString *someProperty;
    }
    
    @property (nonatomic, retain) NSString *someProperty;
    
    + (id)sharedManager;
    
    @end
    

    MyManager.m

    #import "MyManager.h"
    
    @implementation MyManager
    
    @synthesize someProperty;
    
    #pragma mark Singleton Methods
    
    + (id)sharedManager {
        static MyManager *sharedMyManager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedMyManager = [[self alloc] init];
        });
        return sharedMyManager;
    }
    
    - (id)init {
      if (self = [super init]) {
          someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
      }
      return self;
    }
    
    - (void)dealloc {
      // 应该永远不会被调用,放在这里以表清晰。
    }
    
    @end
    

    上面的代码定义了一个叫做 sharedManager 的静态变量(但只在此翻译单元(translation unit)中是全局的),然后在 sharedManager 里初始化了一次,并且永远只有这一次初始化。怎么确保它只被创建一次呢?因为使用了 GCD(Grand Central Dispatch)里面的 dispatch_once 方法。线程安全,完全由操作系统负责,所以就不需要再多担心什么了。

    但如果你不想用 GCD,sharedManager 可以采用下面的代码:

    + (id)sharedManager {
        static MyManager *sharedMyManager = nil;
        @synchronized(self) {
            if (sharedMyManager == nil)
                sharedMyManager = [[self alloc] init];
        }
        return sharedMyManager;
    }
    

    然后就可以在任意位置调用下面这个函数来引用单例了:

    MyManager *sharedManager = [MyManager sharedManager];
    

    我在项目中大量使用了这些代码,例如创建一个单例来处理 CoreLocation 或 CoreData 函数。


    无 ARC 代码

    虽然我并不推荐这样,但如果你没有用 ARC(Automatic Reference Counting)的话,就应该采用下面的代码:

    MyManager.h. 无ARC

    #import "MyManager.h"
    
    static MyManager *sharedMyManager = nil;
    
    @implementation MyManager
    
    @synthesize someProperty;
    
    #pragma mark Singleton Methods
    + (id)sharedManager {
      @synchronized(self) {
          if(sharedMyManager == nil)
              sharedMyManager = [[super allocWithZone:NULL] init];
      }
      return sharedMyManager;
    }
    + (id)allocWithZone:(NSZone *)zone {
      return [[self sharedManager] retain];
    }
    - (id)copyWithZone:(NSZone *)zone {
      return self;
    }
    - (id)retain {
      return self;
    }
    - (unsigned)retainCount {
      return UINT_MAX; //表示此对象无法被释放
    }
    - (oneway void)release {
      // 永不释放
    }
    - (id)autorelease {
      return self;
    }
    - (id)init {
      if (self = [super init]) {
          someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
      }
      return self;
    }
    - (void)dealloc {
      // 应该永远不会被调用,放在这里以表清晰。
      [someProperty release];
      [super dealloc];
    }
    
    @end
    

    相关文章

      网友评论

        本文标题:Objective-C 中的单例

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