3

我创建了一个单例类来跟踪我在 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
4

5 回答 5

6

在几乎所有情况下,单例的意义在于你不关心谁首先实例化它。谁最先呼唤谁就是[Something sharedSomething]创造者。您想使用“如何实现与 ARC 兼容的 Objective-C 单例? ”中给出的模式,这将确保单例只创建一次。

于 2012-04-11T00:51:21.433 回答
2

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

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

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

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

于 2012-04-11T00:51:51.947 回答
1

这可能是最简单的方法:

static MyClass* theInstance = nil;

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

    return theInstance;
}

...所以在你想访问单例的地方,你只是[MyClass sharedInstance]为了获得对实例的引用。

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

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

于 2012-04-11T00:51:20.180 回答
0

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

static SomeClass *_instance = nil;

+ (SomeClass *) instance {
    @synchronized(self) {
        if (!_instance)
            _instance = [[self alloc] init];
    }
    return _instance;
}
于 2012-04-11T00:54:11.207 回答
0

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

+ (SingletonClass *)sharedInstance {
  static SingletonClass *sharedInstance;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sharedInstance = [[SingletonClass alloc] init];
    sharedInstance.property = [Property new];
  });
  return sharedInstance;
}
于 2012-04-11T01:03:30.677 回答