繁体   English   中英

ARC和Objective C子类化

[英]ARC and Objective C Subclassing

我对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关闭时,它会发出编译器警告,但也会像我期望的那样运行。

感谢您提供任何帮助,以帮助我弄清楚为什么会发生这种情况。

定义是否更好:

- (void)playerMessage;

ComputerPlayer类中的方法,并且:

-(void)playerMessage {
   [super playerMessage];

   [self computerOnlyPlayerMessage];

}

那是inheritance点,不是吗? 您将类变量定义(期望)为Player但未定义ComputerPlayer ,如果为ComputerPlayer ,它将仅对“ computer”执行特定的工作。

当然,然后执行:

[Player playerMessage]; // Warning should gone

ps:请投下反对票的人解释原因,并给与他们一个机会

您可以测试它是否是计算机播放器

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

它给您一个错误,因为p2是Player的子类,并且在Player类中没有诸如computerPlayerOnlyMessage这样的方法。 此方法存在于ComputerPlayer类中,因此您应将p2声明为该类型的对象。 在您声明p2的chenge行中:

ComputerPlayer *p2;

首先,不要像声明一样声明它们

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

@properties做到这一点。 原因是ivars没有任何getter或setter,而如果您使用'@properties @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];
    }
}

正如@Greg所说, computerPlayerOnlyMessageComputerPlayer类(而不是其继承的类)公开的方法,因此即使在禁用ARC的情况下编译器报告警告,使用它也是一种不好的做法。

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

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

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

  1. Player类中的computerPlayerOnlyMessage声明为抽象(带有空主体或引发异常,以提醒应在子类中重写该方法)
  2. ComputerPlayer删除computerPlayerOnlyMessage ,而是重写playerMessage 由于多态性,无论您是以Player还是ComputerPlayer身份访问类实例,都将调用正确的实现。

如果computerPlayerOnlyMessage打算做playerMessage工作,只是以一种不同的方式,我会选择选项no。 2

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

这就是我编写示例的方式,在该示例中,我需要向所有Player实例发送“玩家”消息,有时需要专门化,而在其他时间发送特定的“ 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";
    }
}

如您所见,这使您可以将npc像人类玩家一样对待,如果需要,可以询问玩家是否符合NPC协议,因此可以调用所需的协议方法,并根据它们的协议专门引用对象。

以我的拙见,当您开始需要将行为“混入”各种对象时,协议就变得最有意义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM