2011-12-09 37 views
0

我有以下的情況,我不能解析:的Objective-C,階級身份

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

裏面MasterDeck類,在初始化過程中,我呼籲在

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

通話效果error [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因爲」甲板認爲它是一個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

假設上述辛格爾頓執行,爲什麼會甲板認爲它實際上是一個PlayerDeck?

+0

顯示創建此對象的代碼,'self'。您必須無意中創建了PlayerDeck實例 –

+0

如果將MasterDeck直接更改爲子類NSObject並獨立實現super的init方法,會發生什麼情況?如果問題消失,那可能會給你一個線索。也許Deck的init方法錯誤地實例化PlayerDeck。 – Wienke

+0

@Wienke,我想到了,似乎並不是這樣..我在這裏也發佈了Deck的初始化代碼 – JAM

回答

3

所以你寫這個的方式,如果你先創建PlayDeck實例,那麼Deck實例現在是一個PlayDeck。

然後,如果您要創建MasterDeck實例,您對[super init]的調用將盡職盡責地返回先前的PlayDeck實例。

那麼爲什麼甲板是一個單身呢?甲板有兩個單獨的子類,但是你真的在尋找單身甲板嗎?

至少,您可以通過進行此類工作,而不是在每個初始值內設置gInstance。讓類方法做到這一點。只需從每個init中返回自己。另外,除去gInstance不爲空的檢查,一旦你有一個Deck實例,其他Deck的init將總是返回Deck的實例。

但除此之外,我會重新思考這個想法。希望有所幫助。

+0

太棒了!謝謝 – JAM

+0

您還需要刪除Deck的init中的if(gInstance!= NULL)檢查。我真的會從全部3中刪除它。 –

2

你可能想要將你的單例類從實際的類中分離出來。

嘗試在此example其實現爲,

+(id) instance { 
    static dispatch_once_t pred; 
    static MasterDeck *sharedInstance = nil; 
    dispatch_once(&pred, ^{ 
     sharedInstance = [[MasterDeck alloc] init]; 
    }); 
    return sharedInstance; 
} 
1

如果你更換[[self alloc] init][[MasterDeck alloc] init]發生什麼呢?

這可能是某種程度上selfPlayerDeck。爲了確保,你可以在致電+ alloc之前致電NSLog([self description])

編輯

我認爲代碼的有趣的部分你有以上的MasterDeck@implementation的一部分。我的建議是嘗試了很多記錄,包括確定哪些super[self class]是調用[super init]之前,雖然這些可能會誤導......

此外,作爲一個側面說明,我認爲你應該在init調用[self release]如果你正在返回以前創建的實例。

[super init]方法是什麼樣的?你可以進入它,或者它是默認的初始化程序?

編輯2

我認爲你做單身錯了。如果初始化PlayerDeck,則會在Deck中創建一個單例,這是PlayerDeck的一個實例。然後,在初始化MasterDeck時,調用[super init]將返回PlayerDeck已創建的實例。

+0

一直到我'[super init]''MasterDeck'都是'MasterDeck',通過這條線它變成了'PlayerDeck' – JAM

+0

Ed,超級'NSLog(@「Deck認爲它是%@」,[[self class] description]);'打印PlayerDeck。這可以解釋爲什麼MasterDeck認爲它是一個PlayerDeck,但現在......爲什麼Deck認爲它是一個PlayerDeck? – JAM

+0

如果你特別是在第一次調用'+ instance'(或者如果你正在調用''-init''的話)?這條線是什麼樣的? –

1

它看起來像你試圖聰明,但事實是 - 通常電腦更聰明。 :)

你的甲板類在gInstance中緩存了一個實例 - 實際上,它看起來像它可能存儲甲板,PlayerDeck或MasterDeck,這取決於你先調用/實例化的方式和方式。之後,這個實例被init方法返回。

我強烈建議讓這段代碼乾淨可讀。我敢打賭,這個代碼有很多問題 - 但你的問題已經是一個很好的例子。你的邏輯(應該很簡單,我猜)可以更容易地實現。

注 - 我不反對單身人士,但這種代碼堆棧是絕對不行的。在這些行中很難獲得更多的依賴邏輯。 ;)