6

我的问题与这个问题非常相似:Use Singleton In Interface Builder?

唯一的区别是我使用 ARC。因此,如果简化,我的单身人士看起来像这样:

经理.m

@implementation Manager

+ (instancetype)sharedManager {
    __strong static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

@end

所以问题是是否有可能在仍然使用 ARC 的 Interface Builder 中采用它?

当然,我知道在没有 ARC 的情况下重写该类可能更简单,所以这个问题相当学术。:)

4

3 回答 3

9

当 nib 未归档时,它将尝试alloc/initalloc/initWithCoder:类的新实例。

因此,您可以做的是拦截该调用并重新路由它以返回您的单例:

+ (id)sharedInstance {
  static Singleton *sharedInstance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sharedInstance = [[self actualAlloc] actualInit];
  });
  return sharedInstance;
}

+ (id)actualAlloc {
  return [super alloc];
}

+ (id)alloc {
  return [Singleton sharedInstance];
}

- (id)actualInit {
  self = [super init];
  if (self) {
    // singleton setup...
  }
  return self;
}

- (id)init {
  return self;
}

- (id)initWithCoder:(NSCoder *)decoder {
  return self;
}

这允许-init并且-initWithCoder:可以安全地在同一个对象上多次调用。通常不建议允许这样做,但鉴于单身人士已经是“事情可能变得非常不稳定的地方”的情况,这并不是你能做的最糟糕的事情。

于 2012-11-21T23:02:21.423 回答
2

为了完整起见,这是一个可以从 Interface Builder 中使用的 Singleton 实现。区别在于actualAlloc方法。正如[super alloc]仍然会调用[self allocWithZone:]的那样——它不会分配对象。

单例.h

@interface Singleton : NSObject

+ (instancetype)sharedInstance;

@end

单身人士.m

@implementation Singleton

+ (instancetype)sharedInstance {
    __strong static id _sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self _alloc] _init];
    });
    return _sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [self sharedInstance];
}

+ (id)alloc {
    return [self sharedInstance];
}

- (id)init {
    return self;
}

+ (id)_alloc {
    return [super allocWithZone:NULL]; //this is important, because otherwise the object wouldn't be allocated
}

- (id)_init {
    return [super init];
}

@end
于 2012-11-27T19:21:56.737 回答
0

@Eugene,来自 iOS 文档集,“出于历史原因,alloc调用allocWithZone:.”,因此,无需重新实现该alloc方法。

于 2013-05-11T05:32:54.323 回答