Подтвердить что ты не робот

Какой правильный метод для подкласса одноэлементного класса в Objective -C?

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

 [SuperClass sharedInstance] //-> instance of SuperClass
 [SubClass sharedInstance] //-> instance of Class

Ответ 3

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

Ответ 4

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

// 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 позволяет компилятору проверить тип результата этого метода: itll be Sprocket, когда вы вызываете его как +[Sprocket defaultSprocket], но SprocketSubclass, когда вы вызываете его как +[SprocketSubclass defaultSprocket].

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

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

Ответ 5

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

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

Ответ 6

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

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

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

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

Ответ 7

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

Ответ 8

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

Класс 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 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]!

Ответ 9

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

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

Н

#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

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

Н

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

M

@implementation SomeSubclass
CREATE_SHARED_INSTANCE 
@end

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

[[SomesSubclass SharedInstance] someMethod];

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

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

Ответ 10

@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