【问题标题】:Instantiating A Singleton Class实例化一个单例类
【发布时间】:2012-04-11 00:44:01
【问题描述】:

我创建了一个单例类来跟踪我在 iPhone 应用上的数据。我知道单例只需要实例化一次,但是实例化它的最佳位置是什么?这应该在 appDelegate 中完成吗?我希望能够从多个类中调用这个单例(其中包含一个 NSMutableArray),以便我可以访问该数组。

这是我写的课程:

#import "WorkoutManager.h"

static WorkoutManager *workoutManagerInstance;

@implementation WorkoutManager
@synthesize workouts;

+(WorkoutManager*)sharedInstance {
    if(!workoutManagerInstance) {
        workoutManagerInstance = [[WorkoutManager alloc] init];
    }
    return workoutManagerInstance;
}

-(id)init {
    self = [super init];
    if (self) {
        workouts = [[NSMutableArray alloc] init];
    }
    return self;
}

@end

【问题讨论】:

  • 链接似乎是关于实现单例。我已经有我的书面和功能。我在我的一个类中的一个 IBAction 中实例化它,但是我很困惑我是否应该在其他地方实例化它以便它是全局的?
  • 这些答案的重点是您不必在代码中的任何地方实例化它。第一次去使用它会自动实例化。
  • 即使它在 IBAction 之类的东西中使用?还是应该在类头中实例化?

标签: iphone objective-c cocoa-touch


【解决方案1】:

在几乎所有情况下,单例的意义在于你不关心谁首先实例化它。谁第一个打电话给[Something sharedSomething],谁就是创建者。您想使用“How do I implement an Objective-C singleton that is compatible with ARC?”中给出的模式,它将确保单例只创建一次。

【讨论】:

    【解决方案2】:

    单例通常是惰性实例化的——第一次访问它们时,会创建实例并从访问方法返回。对访问方法的后续调用仅返回已创建的实例。

    标准模式是: 1. 获取锁或以其他方式使以下线程安全(即dispatch_once())。 2. 检查单实例是否已经创建。 3. 如果没有,创建它。 4. 释放锁定(如果适用)。 5. 返回实例。

    如果您出于某种原因需要,可以提前创建实例。类方法+load 是在将类添加到运行时时由运行时发送的,这是在您的应用程序执行的早期阶段。 (+initialize 似乎也是一个候选者——它是在类收到它的第一条(其他)消息(也不包括+load)之前由运行时发送的——但它实际上并没有给你任何东西,因为它'将在您发送 sharedInstance 之前立即发送。)

    gcc __constructor__ function attribute 也可以工作(在 clang 中也是如此),尽管被记录为没有为 ObjC 实现。在输入main() 之前将调用具有此属性的函数。不过,我不太确定此选项的内存管理含义。运行时应该全部设置好,但还没有自动释放池。

    【讨论】:

    • 这里非常有用的技术。 +load 是一个特别有用的了解工具(尽管您不应该经常需要它)。
    【解决方案3】:

    这可能是最简单的方法:

    static MyClass* theInstance = nil;
    
    + (MyClass*) sharedInstance {
        @synchronized(self) {
            if (! theInstance) {
                theInstance = [[MyClass alloc] init];
            }
        }
    
        return theInstance;
    }
    

    ...所以在您想要访问单例的地方,您只需执行[MyClass sharedInstance] 即可获得对实例的引用。

    请注意,这不能防止人们在您的单例类上手动调用 allocinit 来创建其他实例。如果您需要这样做,您可以以与上述类似的方式实现init,以防止使用allocinit 创建/返回其他实例。

    然而,在实践中,单例类最常使用sharedInstance 方法(有时在命名上会有细微的变化,例如[UIApplication sharedApplication])。

    【讨论】:

    • 我推荐stackoverflow.com/questions/7568935/…的答案中给出的GCD模式。 @synchronize 解决方案调用起来有点贵,而且自从添加了 dispatch_once 之后就没有理由支付这个成本了。
    • 任何一种方法都行,是的。我个人更喜欢@synchronized;我只是觉得它更具可读性。
    【解决方案4】:

    通常单例类在第一次被访问时被实例化:

    static SomeClass *_instance = nil;
    
    + (SomeClass *) instance {
        @synchronized(self) {
            if (!_instance)
                _instance = [[self alloc] init];
        }
        return _instance;
    }
    

    【讨论】:

      【解决方案5】:

      我正在使用此代码来实例化单例。 GCD 负责同步

      + (SingletonClass *)sharedInstance {
        static SingletonClass *sharedInstance;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
          sharedInstance = [[SingletonClass alloc] init];
          sharedInstance.property = [Property new];
        });
        return sharedInstance;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-21
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多