ARC和Objective C Subclassing

时间:2014-02-21 10:33:29

标签: ios iphone objective-c ios7 automatic-ref-counting

我对Obj C和iOS开发很新,我遇到了一个问题,我不明白为什么会这样。

因此,要设置场景,我有2个模型类,播放器和计算机播放器以及控制器。

播放器:

@interface Player : NSObject
-(void) playerMessage;
@end

ComputerPlayer:

@interface ComputerPlayer : Player
-(void) computerPlayerOnlyMessage;
@end

控制器:

@interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}


@implmentation ViewController
-(void)viewDidLoad
{
 p1 = [[Player alloc]init];
 p2 = [[ComputerPlayer alloc]init];

 [p1 playerMessage];
 currentPlayer = p2;
 [currentPlayer computerPlayerOnlyMessage];
}

然而,上面的问题是[currentPlayer computerPlayerOnlyMessage]在打开ARC时出现编译器错误。当ARC关闭时,它会发出编译器警告但会按照我的预期运行。

感谢任何帮助,以帮助我了解为什么会发生这种情况。

6 个答案:

答案 0 :(得分:2)

定义不是更好:

- (void)playerMessage;
<{1}}类中的

方法和:

ComputerPlayer

这是-(void)playerMessage { [super playerMessage]; [self computerOnlyPlayerMessage]; } 的一点,不是吗?您已将(期望)您的类变量定义为inheritance但不是Player,如果它是ComputerPlayer,则它将仅为“计算机”执行特定的工作。

当然,你执行:

ComputerPlayer

p.s:请投票的人请解释原因,给予机会同意

答案 1 :(得分:1)

如果是电脑播放器,您可以进行测试

 if ([currentPlayer isKindOfClass:[ComputerPlayer class]])
     [(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];

答案 2 :(得分:0)

它会给你一个错误,因为p2是Player的子类,你没有像Player类中的computerPlayerOnlyMessage这样的方法。此方法存在于ComputerPlayer类中,因此您应将p2声明为此类型的对象。将p2声明为:

的chenge行
ComputerPlayer *p2;

答案 3 :(得分:0)

首先,而不是将它们声明为像

这样的ivars
@interface viewController : UIViewController{
    Player *p1;
    Player *p2;
    Player *currentPlayer;
}

使用@properties执行此操作。原因是ivars没有任何getter或setter,而如果你使用'@properties则会自动生成它们,所以改为

@interface viewController : UIViewController
// This will auto generate the ivars, getters and setters
@property (nonatomic, strong) Player *p1;
@property (nonatomic, strong) Player *p2;
@property (nonatomic, strong) Player *currentPlayer;
@end

然后你可以做

@implmentation ViewController
-(void)viewDidLoad
{
    p1 = [[Player alloc]init];
    p2 = [[ComputerPlayer alloc]init];

    [p1 playerMessage];
    currentPlayer = p2;

    // Could also replace below with [currentPlayer isKindOfClass:[ComputerPlayer class]] use which ever fits best for you and what you want.
    // If using below, if you decided to subclass ComputerPlayer class anything that subclassed 
    // from ComputerPlayer will also make it into this if statement. If iskindOfClass: is used 
    // Only objects that are kind of class will make it into this if statement.
    if([[currentPlayer class] isSubclassOfClass:[ComputerPlayer class]]) {
        [(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
    }
}

答案 4 :(得分:0)

正如@Greg所说,computerPlayerOnlyMessageComputerPlayer类公开的方法,而不是它继承的类,所以即使编译器在ARC被禁用时报告警告,它也会是使用它的不良做法。

明确询问类实例是否实现了该方法,这是一种有效的解决方法。但是在我看来,解决方案缺乏良好的OO设计,除非我有充分的理由(有时它很方便),否则我不会使用它 - 在其他OO语言中,这是不可能的。

多态性允许使用类的实例,就好像它是其超类之一,但不是相反。您可以覆盖和专门化超类方法,但是您不能指望超类知道它的任何子类实现的方法。

我建议2种可能的解决方案:

  1. computerPlayerOnlyMessage类中的Player声明为抽象(使用空体或抛出异常,提醒您应该在子类中覆盖该方法)
  2. computerPlayerOnlyMessage移除ComputerPlayer,改为覆盖playerMessage。多亏了多态,无论您是以Player还是ComputerPlayer
  3. 访问类实例,都会调用正确的实现。

    如果computerPlayerOnlyMessage意图执行playerMessage所做的事情,只是以不同的方式,我会选择选项号。 2

答案 5 :(得分:0)

这似乎是使用协议的好地方。

以下是我编写示例的方法,我需要向玩家的所有实例发送“播放器”消息,特殊场合,并在其他时间发送特定的“npc”消息。

@protocol <NPC>
@property (nonatomic) NSString *someNPCString;
- (void)foo;
- (void)bar;
@end

@interface Player : NSObject
@end
@implementation Player
- (void)message
{
    NSLog(@"message");
}
@end

@interface AI : Player <NPC>
@end
@implementation AI
@synthesize someNPCString;
- (void)foo
{
    NSLog(@"foo");
}
- (void)bar
{
    NSLog(@"bar");
}
@end

@interface viewController : UIViewController
@property (nonatomic) NSArray *humans;
@property (nonatomic) NSArray *npcs;
@end
@implmentation ViewController
-(void)viewDidLoad
{
    id<Player> currentPlayer = nil;
    humans = [NSArray arrayWithObject:[Player new]];
    npcs = [NSArray arrayWithObjects:[AI new], [AI new], nil];

    // message all player types, regardless of player or npc
    for (Player *player in [humans arrayByAddingObjectsFromArray:npcs])
    {
        currentPlayer = player;
        [player message];
        if([player conformsToProtocl:@protocol(NPC)])
        {
            [(id<NPC>)player foo];
        }
    }

    for (id<NPC>npc in npcs)
    {
        [npc bar];
        npc.someNPCstring = @"str";
    }
}

正如你所看到的,这可以让你像人类玩家一样对待npcs,如果你需要,让你问你的玩家是否符合NPC协议,所以你可以调用所需的协议方法,让你通过他们的协议。

当我开始需要将行为“混入”各种对象时,协议开始最有意义。