2010-03-09 4 views
1

Я немного смущен этим фрагментом кода (представленным в руководстве CocoaFundamentals), который переопределяет некоторые из методов при создании экземпляра singleton.Пример запроса Apple Singleton?

static id sharedReactor = nil; 

+(id)sharedInstance { 
    if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init]; 
    return sharedReactor; 
} 

.

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

-(id)retain { 
    return self; 
} 

В коде, где одноточечно экземпляр создан метод + sharedInstance называет [супер allocWithZone: NILL] от суперкласса (в моем случае это NSObject) allocWithZone выше вызывается только, если вы пытаетесь использовать его для создания нового синглтона.

Я немного смущен, это использование сохранения, особенно видение, поскольку сохранение также переопределяется, чтобы вернуть себя. Может кто-нибудь объяснить это, это не могло быть написано:

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

-(id)retain { 
    return self; 
} 

EDIT_001:

На основе замечаний и чтения различных сообщений в Интернете я решил пойти со следующим (смотри ниже) У меня есть выбранный для совместного использования одноэлементного подхода, где в случае необходимости у меня будет возможность создать второй или третий экземпляр. Также на этом этапе, поскольку я использую только одноэлемент для части модели MVC для простого приложения для iPhone, я решил оставить защиту потоков. Я знаю, что это важно, и по мере того, как я больше знаком с программированием на iPhone, я, скорее всего, буду использовать + инициализацию (имея в виду проблему подкласса, где она может быть вызвана дважды). Также я добавил dealloc, во-первых, чтобы зарегистрировать сообщение, если синглтон быть освобожденным, но и очищать вещи должным образом, если синглтон больше не требуется.

@interface SharedManager : NSObject 
+(id)sharedInstance; 
@end 

@implementation SharedManager 

static id myInstance = nil; 

+(id)sharedInstance { 
    if(myInstance == nil) { 
     myInstance = [[self alloc] init]; 
    } 
    return myInstance; 
} 

-(void)dealloc { 
    NSLog(@"_deal: %@", [self class]); 
    [super dealloc]; 
    myInstance = nil; 
} 
@end 

В ходе тестирования я обнаружил, что у меня был набор статической переменной всухую в dealloc или она сохраняет свой указатель на исходный объект. Первоначально я был немного смущен этим, так как я ожидал, что область действия static будет экземпляром, я думаю, что это класс, что имеет смысл.

веселит Гэри

ответ

5

Во-первых, не используйте этот код. Практически никогда не было причины делать все это для простого синглтона. Apple демонстрирует «Forced Singleton», поскольку невозможно создать два из них. Это очень редко действительно нужно. Вы почти всегда можете использовать подход «shared singleton», используемый большинством объектов Cocoa, которые имеют одноэлементный конструктор.

Вот мой предпочтительный способ реализации совместного синглтон:

+ (MYManager *)sharedManager 
{ 
    static MYManager *sharedManager = nil; 
    if (sharedManager == nil) 
    { 
     sharedManager = [[self alloc] init]; 
    } 
    return sharedManager; 
} 

Вот так. Никакой другой код не требуется. Звонящие, которые используют +sharedManager, получат общий экземпляр. Абоненты, которые звонят +alloc, могут создавать уникальные экземпляры, если они действительно этого хотят. Так работают такие знаменитые «синглтоны», как NSNotificationCenter. Если вы действительно хотите получить свой собственный центр уведомлений, нет причин, по которым класс должен его запрещать. Этот подход имеет следующие преимущества:

  • Меньше кода.
  • Более гибкий в случаях, когда полезный экземпляр не является общим.
  • Самое главное: код делает то, что он говорит. Вызывающий, который считает, что он делает уникальный экземпляр с +alloc, не сталкивается с неожиданным поведением «призрачного действия на расстоянии», которое требует, чтобы он знал внутреннюю детализацию реализации объекта.

Если вы действительно нужны вынужденного синглтон, поскольку объект в картах вопроса к уникальному ресурсу, который не может быть общими (и это действительно редко можно встретить такую ​​ситуацию), то вы все равно не должны использовать +alloc фокусов для обеспечения его соблюдения. Это просто маскирует ошибку программирования при попытке создать новый экземпляр. Вместо этого вы должны поймать ошибку программирования таким образом:

+ (MYManager *)sharedManager 
{ 
    static MYManager *sharedManager = nil; 
    if (sharedManager == nil) 
    { 
     sharedManager = [[self alloc] initSharedManager]; 
    } 
    return sharedManager; 
} 

- (id)init 
{ 
    NSAssert(NO, @"Attempting to instantiate new instance. Use +sharedManager."); 
    return nil; 
} 

// Private method. Obviously don't put this in your .h 
- (id)initSharedManager 
{ 
    self = [super init]; 
    .... 
    return self; 
} 
+1

Возможно, вы захотите обновить это, чтобы обсудить проблему безопасности потоков. У Майка Эша есть хорошая статья о том, что наряду с другими проблемами с одиночным ядром: http://www.mikeash.com/pyblog/friday-qa-2009-10-02-care-and-feeding-of-singletons.html – nall

+0

Лучше: читатели должны проверить почту Майка Эша. Это чрезвычайно важно, как это расширить для обеспечения безопасности потоков. Проблемы защиты потоков в общих синглетах влияют только на первоначальное создание. Для меня очень редко встречается такая проблема с потоками из-за того, что я обычно обрабатываю потоки (в моем коде крайне маловероятно, что первое использование синглтона было бы на рабочем потоке). Тем не менее, у меня возникает соблазн использовать использование + инициализации Майка, потому что это так дешево для реализации, и я думаю, что проблема с слишком ранним началом в большинстве случаев маловероятна. –

+1

@Rob это все еще не запрещает несколько экземпляров. Он только «запрещает» их по соглашению. Питер Хосей написал отличный пост о том, как более правильно реализовать синглтоны: http://boredzo.org/blog/archives/2009-06-17/doing-it-wrong –

3

Существует хороший пример различных методов одноэлементных с комментариями здесь на SO: What does your Objective-C singleton look like?

Если это поможет, то пример имеет другой подход к allocWithZone: который возвращает ноль.

Смежные вопросы