Использовать Singleton In Interface Builder?

У меня есть синглтон, настроенный так:

static Universe *instance;

+ (Universe *)instance { return instance; }

+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        instance = [[Universe alloc] init];
    }
}

- (id) init
{
    self = [super init];
    if (self != nil) {
        self.showHistory = YES;
    }
    return self;
}

но теперь я понимаю, что хотел бы создать экземпляр из Interface Builder. Я думал о том, чтобы просто использовать метод init, например,

    if (instance) 
         return instance;

Это плохая идея? Я бы предпочел, чтобы IB подобрал экземпляр, уже созданный в методе +initialize.

Ответы

Ответ 1

Это можно сделать. Существует раздел об этом в Cocoa Design Patterns by Buck и Yachtman.

В вашем случае вы можете сделать что-то по строкам:

static Universe *instance;

+ (Universe *)instance { return instance; }

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

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

+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        instance = [[Universe hiddenAlloc] init];
    }
}

- (id)init
{
  if(instance==nil) // allow only to be called once
  {
    // your normal initialization here
  }
  return self;
}

Затем код загрузки nib правильно подбирает одноэлементный вызов через его вызов [[Universe alloc] init], и вы все равно можете использовать instance в своем коде, как и раньше.

В книге более подробно и рекомендуется внедрить new и allocWithZone (как просто как return [self alloc];), так и оповещения об ошибках, чтобы поймать copyWithZone и mutableCopyWithZone попытки для хорошей оценки.

Ответ 2

Это произойдет. Вы можете избежать этого, если вы измените его на:

if(instance) {
    [self release];
    return instance;
}

но он все еще немного пахнет мне. Мне любопытно, что вы используете для одиночных игр в IB; Я подозреваю, что избегаю этой конструкции в своем коде.