1

在其中一项任务中,我必须为游戏逻辑重写超类的 getter 方法(因此该方法将获取游戏逻辑的子类而不是原始的)。

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 方法。(仅供参考,CardGameViewController 及其子类都没有 *game 的 setter 方法)

所以我有点困惑。请帮忙!

4

1 回答 1

4

The problem here is that you have two versions of _game. Since the introduction of the new ABI (64-bit Mac and all iOS), each subclass can create its own ivars without tromping all over its superclass's ivars (even if they're named the same). And ivars created by @synthesize are private. Now hold that thought and let's see what's happening:

  • In your superclass, you declare a property that has a getter and setter (though you almost certainly don't mean to have a setter…) You override the getter. The compiler says "but you still want me to create a setter for you, so I'll create an ivar to match it."

  • In your subclass, you declare no new properties. You may think you do, but it's just the same property that comes from the superclass; it's not a new property. There's already a getter and setter in the superclass, so there's no need for the compiler to create an ivar.

  • You then reference an ivar that does not exist in your subclass. It only exists as a private ivar in the superclass. The compiler can't see that (and wouldn't let you access it even if it could).

The typical solution to this problem is, rather than overriding -game, just provide a class method called +gameClass and have it return the correct class to instantiate. (See +layerClass in UIView for an example of this pattern.)

于 2013-05-07T15:06:57.710 回答