2013-05-07 44 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