2013-05-07 43 views
1

在其中一項任務中,我必須重寫超類的遊戲邏輯的getter方法(所以該方法將獲得遊戲邏輯的子類而不是原來的方法)。如何知道是否未聲明@synthesize會導致「使用未聲明的標識符」?

CardGameViewController.h:

#import <UIKit/UIKit.h> 
#import "Deck.h" 
#import "CardGame.h" 

@interface CardGameViewController : UIViewController 
@property (nonatomic) NSUInteger startingCardCount; // abstract 
@property (strong, nonatomic) CardGame *game; 

- (Deck *)createDeck; // abstract 
- (void)updateCell:(UICollectionViewCell *)cell usingCard:(Card *)Card; // abstract 

@end 

CardGameViewController.m:

#import "CardGameViewController.h" 

... 

// no @synthesize here, but works fine. 

- (CardGame *)game 
{ 
    if (!_game) _game = [[CardGame alloc] initWithCardCount:self.startingCardCount 
               usingDeck:[self createDeck]]; 
    return _game; 
} 

... 

@end 

SetCardGameViewController.m:

... 

@interface TSSetCardGameViewController() 

@property (strong, nonatomic) CardGame *game; 

@end 

@implementation TSSetCardGameViewController 

@synthesize game = _game; // Compiler *will* complain if this line is commented out. 

- (CardGame *)game 
{ 
    if (!_game) _game = [[SetCardGame alloc] initWithCardCount:self.startingCardCount 
                usingDeck:[self createDeck]]; 
    return _game; 
} 

... 

@end 

然後我得到了 「使用未聲明的標識符」 爲 「_game」 。所以我宣佈

@property (strong, nonatomic) CardGame *game; 

但我得到了同樣的錯誤,所以我用「self.game」來代替,這就造成了不好的訪問異常。 我無法在谷歌找到任何東西,所以我修修補補周圍,直到我發現,這解決了這個問題:

@synthesize game = _game; 

現在,我的問題是爲什麼。我的理解是Xcode的新版本爲我做了合成,除非我重寫它的getter和setter。我確實重寫了getter,但不是setter,所以Xcode在技術上應該自動包含它。證明是,Xcode沒有抱怨,直到我分類CardGameViewController,特別是取消了getter方法。 (FYI CardGameViewController還是其子類,既沒有對*遊戲setter方法)

所以我有點困惑。請幫忙!

+0

這不是Xcode的,做自動合成,它的編譯器。 – 2013-05-07 12:03:49

+0

「SetCardGame」的屬性是什麼? – 2013-05-07 12:06:34

+0

ott //我不確定你在問什麼。它是CardGame的一個子類,有很多方法來計算紙牌遊戲的分數。 – Skishnot 2013-05-07 12:13:29

回答

4

這裏的問題是,你有_game兩個版本。自推出新的ABI(64位Mac和所有iOS)以來,每個子類都可以創建自己的ivars,而不會對其所有超類的ivars(即使它們命名相同)發生衝突。而由@synthesize創建的ivars是私人的。現在持有這種想法,讓我們看看發生了什麼:

  • 在你的超類,請聲明具有一個getter和setter(雖然你幾乎可以肯定,並不意味着有一個setter ......),你重寫獲取方法的屬性。編譯器說:「但你仍然希望我爲你創建一個setter,所以我會創建一個ivar來匹配它。」

  • 在你的子類,聲明沒有新的特性。你可能認爲你是這樣做的,但它只是來自超類的相同屬性;這不是一個新的屬性。超類中已經有了一個getter和setter,所以編譯器不需要創建一個ivar。

  • 然後你引用一個不在子類中存在的伊娃。它只作爲超級中的私人伊娃而存在。編譯器無法看到(即使可以,也不會讓你訪問它)。

典型的解決這個問題,而不是覆蓋-game,只是提供了一種稱爲+gameClass一個類的方法,並使其返回正確的類實例化。 (這種模式的一個例子見UIView+layerClass。)

+0

非常感謝你! – Skishnot 2013-05-07 15:16:38