Objective-C, класс идентичности - PullRequest
       1

Objective-C, класс идентичности

0 голосов
/ 09 декабря 2011

У меня следующая ситуация, я не могу разрешить:

@interface Deck : NSObject
@interface MasterDeck : Deck 
@interface PlayerDeck : Deck

Внутри MasterDeck класса, в рамках инициализации, я вызываю

[self cutDeckImageIntoCards]; // We don't get to execute this method

Вызов результатов вошибка [PlayerDeck cutDeckImageIntoCards]: unrecognized selector sent to instance

Действительно, PlayerDeck не имеет этого метода ... но почему он вообще вызывается?

После просмотра инициализации MasterDeck я добавилнесколько операторов отладки:

static MasterDeck *gInstance = NULL;

+(MasterDeck *) instance {
    @synchronized(self) {
        if (gInstance == NULL) {
            gInstance = [[self alloc] init];
        }
    }

    return gInstance;
}

-(id) init {

    if (gInstance != NULL) {
        return gInstance;
    }

    // MasterDeck
    self = [super init];  
    // PlayerDeck

    if (self) {
       // Lots of stuff
       [self cutDeckImageIntoCards]
       // Some more stuff
     }

    gInstance = self;
    return gInstance;
}

Хорошо, поэтому MasterDeck является PlayerDeck, потому что 'Deck считает, что это PlayerDeck ... Колода подтверждает

Колода создается следующим образом:

static Deck *gInstance = NULL;

+(Deck *) instance {
    @synchronized(self) {
        if (gInstance == NULL) {
            gInstance = [[self alloc] init];
        }
    }

    return gInstance;
}

-(id) init {

    if (gInstance != NULL) {
        return gInstance;
    }

    self = [super init];

    if (self) {               
       // Do something
    }

    NSLog(@"Deck thinks it's a %@", [[self class ]description]); // PlayerDeck

    gInstance = self;
    return gInstance;
}

Итак, еще раз

  • @interface Deck : NSObject

Если предположить, что выше реализации Singleton, почему бы Deck думал, что это на самом деле PlayerDeck

Ответы [ 4 ]

3 голосов
/ 09 декабря 2011

Таким образом, как вы написали это, если вы сначала создаете экземпляр PlayDeck, то экземпляр Deck теперь является PlayDeck.

И затем, если вы собираетесь создать экземпляр MasterDeck, ваш вызов [super init] покорно возвращает этот предыдущий экземпляр PlayDeck.

Так почему же Deck вообще синглтон?В колоде есть два подкласса, которые являются синглетонами, но действительно ли вы ищете также и одиночную колоду?

Как минимум, вы можете сделать такую ​​работу, не устанавливая gInstance из каждого init ,Пусть метод класса сделает это.Просто верни себя от каждого из инициатов.Кроме того, уберите проверку того, что gInstance не равен NULL, другая инициализация колоды всегда будет возвращать экземпляр колоды, если у вас есть экземпляр колоды.

Но помимо этого я бы немного переосмыслил эту идею.Надеюсь, это поможет.

2 голосов
/ 09 декабря 2011

Вы, вероятно, захотите отделить ваш синглтон-класс от реального класса.

Попробуйте реализовать его, как в этом примере ,

+(id) instance {
    static dispatch_once_t pred;
    static MasterDeck *sharedInstance = nil;
    dispatch_once(&pred, ^{
        sharedInstance = [[MasterDeck alloc] init];
    });
    return sharedInstance;
}
1 голос
/ 09 декабря 2011

Похоже, вы пытаетесь быть умным, но факт - часто компьютер еще умнее. :)

Ваш класс колоды кэширует экземпляр в gInstance - фактически, похоже, он может хранить колоду, PlayerDeck или MasterDeck, в зависимости от того, что и как вы вызываете / создаете первым. После этого этот экземпляр возвращается этим методом init.

Я настоятельно рекомендую сделать этот код чистым и читабельным. Могу поспорить, что у этого кода много проблем, но ваша проблема уже хороший пример. Ваша логика (которая должна быть простой, я думаю) может быть реализована намного проще.

Примечание. Я не против синглетонов, но такого рода кодирование не допускается. Трудно получить больше логики зависимости в этих строках. ;)

1 голос
/ 09 декабря 2011

Что произойдет, если вы замените [[self alloc] init] на [[MasterDeck alloc] init]?

Может быть, что-то self есть PlayerDeck. Чтобы убедиться, что вы могли бы NSLog([self description]) прямо перед вызовом + alloc.

Редактировать

Я предполагаю, что интересная часть кода, который вы имеете выше, является частью @implementation из MasterDeck. Мое предложение было бы попробовать намного больше регистрации, включая определение того, что super и [self class] перед вызовом [super init], хотя это может вводить в заблуждение ...

Также, как примечание, я считаю, что вам следует вызвать [self release] в init, если вы возвращаете ранее созданный экземпляр.

Как выглядит метод [super init]? Можете ли вы вмешаться или это инициализатор по умолчанию?

Редактировать 2

Я думаю, ты неправильно делаешь синглтоны. Если вы инициализируете PlayerDeck, это создаст синглтон в Deck, который является экземпляром PlayerDeck. Затем позже, когда вы инициализируете MasterDeck, вызов [super init] вернет экземпляр, уже созданный PlayerDeck.

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