Какой правильный метод для создания подкласса одноэлементного класса в Objective -C? - PullRequest
14 голосов
/ 03 августа 2010

Я создал одноэлементный класс, и я хочу создать класс, который является подклассом этого одноэлементного класса, каков правильный метод для этого

Ответы [ 10 ]

20 голосов
/ 03 августа 2010

Я не знаю, в частности, об Objective-C, но в целом одноэлементные классы должны предотвращать создание подклассов. Если у вас есть экземпляр базового класса и экземпляр подкласса, то у вас фактически есть два объекта, которые вы можете рассматривать как экземпляры базового класса "singleton", не так ли?

Как только у вас есть два экземпляра, на самом деле это уже не одиночка ... и это оставляет в стороне возможности того, что существует несколько подклассов или что сам подкласс позволяет создавать несколько экземпляров.

Конечно, вы можете изменить свой базовый класс, чтобы у него был способ получить один экземпляр по умолчанию, но это не совсем то же самое, что сделать его одиночным.

13 голосов
/ 03 августа 2010

Если Джон не убедил вас не делать этого, вы должны сделать это следующим образом:

В вашем суперклассе инициализируйте ваш экземпляр singleton с [[[self class] alloc] init], чтобы вы всегда получали экземпляр класса, с которым вы вызываете метод sharedInstance. И вам не нужно перезаписывать метод sharedInstance в вашем подклассе.

 [SuperClass sharedInstance] //-> instance of SuperClass
 [SubClass sharedInstance] //-> instance of Class
8 голосов
/ 12 апреля 2013

Я сделал пример «базового класса» для синглтона, вы можете проверить его здесь: https://github.com/stel/DOSingleton

6 голосов
/ 16 марта 2013

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

// this code goes in the implementation of the superclass

static Sprocket *defaultSprocket;

+ (instancetype) defaultSprocket
{
    if (defaultSprocket == nil)
        defaultSprocket = [[[self class] alloc] init];
    return defaultSprocket;
}

Этот подход имеет следующие преимущества:

  • Использование [self class] позволяет, например, [SprocketSubclass defaultSprocket] вернуть экземпляр SprocketSubclass вместо Sprocket
  • Использование instancetype позволяет компилятору проверить тип результата этого метода:это будет Sprocket, когда вы вызываете его как +[Sprocket defaultSprocket], но SprocketSubclass, когда вы вызываете его как +[SprocketSubclass defaultSprocket].

Примечательно, что вы можете определить этот метод доступа в базовом классе итогда вам не нужно ничего делать в подклассах!

(Шляпа подсказывает NSHipster для , объясняя, почему instancetype такой крутой и bbum для , напоминая мне об этом недавно.)

3 голосов
/ 21 сентября 2015

Если то, что вы ищете, это быстрый способ установки новых синглетонов. Этот псевдо-абстрактный одноэлементный базовый класс я использую:

Многоразовый базовый класс

H

#define CREATE_SHARED_INSTANCE          \
+ (instancetype)sharedInstance {        \
    static dispatch_once_t once;        \
    static id instance = nil;           \
    dispatch_once(&once, ^{             \
        instance = [[self alloc] init]; \
    });                                 \
    return instance;                    \
}

@interface SharedObject : NSObject
+ (instancetype)sharedInstance;
@end

M

@implementation SharedObject
+ (instancetype)sharedInstance {
    [NSException raise:@"Call to unimplemented sharedInstance" format:@"%@ does not implement sharedInstance.", NSStringFromClass([self class])];
    return nil;
}
@end

Тогда каждый подкласс

H

#import "SharedObject.h" 
@interface SomeSubclass : SharedObject
@end

M

@implementation SomeSubclass
CREATE_SHARED_INSTANCE 
@end

... и использовать как любой синглтон.

[[SomesSubclass SharedInstance] someMethod];

Если вы вызовете абстрактный базовый класс или забудете включить CREATE_SHARED_INSTANCE в свой подкласс, вы получите дружественное исключение.

Таким образом, вы можете легко устанавливать новые синглтоны без потери производительности.

1 голос
/ 13 декабря 2015

Самый простой способ добиться этого - реализовать стандартный одноэлементный метод доступа как в классе, так и в подклассе.Таким образом, каждый класс ведет себя как правильный синглтон, то есть существует только один экземпляр обоих.Если вы попытаетесь повторно использовать метод доступа родительского класса в подклассе, а затем, если вы используете оба класса, вы рискуете вернуть метод доступа неверному экземпляру, поскольку их поведение будет зависеть от порядка доступа к ним.

Вы не должны использовать тип экземпляра для одноэлементного метода доступа, чтобы предотвратить эту ошибку.Вы заметите, что Apple не использует его для своих синглетонов, например, UIApplication и CKContainer.

Если вы хотите, чтобы существующий код, который обращается к одноэлементному методу суперкласса, получил экземпляр подкласса, то, скорее всего, вам нужноРедизайн, см. ответ MrJre.

0 голосов
/ 30 июля 2015

У меня была такая же проблема.Вот как это решить: вам нужно использовать статический словарь для подкласса синглтона.Например:

Класс A: NSObject -> Singleton

Класс B: A

Класс C: A

@implementation A

// Dictionary that holds all instances of API subclasses
static NSMutableDictionary *_sharedInstances = nil;

+ (instancetype)sharedInstance
{
    id sharedInstance = nil;
    @synchronized(self)
    {
       NSString *instanceClass = NSStringFromClass(self);

       if (_sharedInstances == nil)
           _sharedInstances = [NSMutableDictionary dictionary];

       // Looking for existing instance
       sharedInstance = [_sharedInstances objectForKey:instanceClass];

       // If there's no instance – create one and add it to the dictionary
       if (sharedInstance == nil) 
       {
          sharedInstance = [[super allocWithZone:nil] init];
          [_sharedInstances setObject:sharedInstance forKey:instanceClass];
       }
   }
   return sharedInstance;

}

Теперь вы можете без проблем использовать [B sharedInstance] и [C sharedInstance]!

0 голосов
/ 25 февраля 2014
@interface SingletonObjC : NSObject
+ (id) sharedInstance;
@end

@implementation SingletonObjC

+ (id) sharedInstance
{
    static dispatch_once_t pred;
    static id sharedInstance = nil;

    dispatch_once(&pred, ^{ sharedInstance = [[self alloc] init]; });
    return sharedInstance;
}

@end
0 голосов
/ 25 октября 2012

У меня была похожая проблема, и я решил, как создать единый класс-обертку, который обладает всеми дополнительными функциями.Этот синглтон-класс содержит исходный синглтон (в качестве переменной-члена используется экземпляр синглтона).Таким образом, вы можете избежать подвохов.

0 голосов
/ 19 сентября 2012

У меня была похожая проблема, у меня было несколько целей, которые должны были иметь несколько разные реализации синглтона: каждая цель включала бы базовый класс + определенный подкласс. Это было достигнуто написанием базового класса следующим образом:

+ (SingletonBaseClass*) sharedInstance {
    static SingletonBaseClass * sharedInstance = nil;
    if (!sharedInstance) {
        sharedInstance = [[[self class] alloc] init];
        [sharedInstance customInit];
    }
    return sharedInstance;
}

Разница в ключах [self class] вместо фактического имени класса. Таким образом, когда мы вызываем: [SingletonSubclass sharedInstance] создается правильный объект.

Обратите внимание, что это особый случай, в общем случае я согласен с предыдущими ответами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...