[英]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所说, computerPlayerOnlyMessage
是ComputerPlayer
类(而不是其继承的类)公开的方法,因此即使在禁用ARC的情况下编译器报告警告,使用它也是一种不好的做法。
明确询问类实例是否实现了该方法,但这是一种可行的解决方法。 但是我认为解决方案缺乏良好的OO设计,除非有充分的理由(在某些情况下它很方便),否则我不会使用它-在其他OO语言中是不可能的。
多态允许类的实例被当作其超类之一使用,但不能相反。 您可以覆盖和专门化超类方法,但是您不能期望超类知道其任何子类实现的方法。
我建议两种可能的解决方案:
Player
类中的computerPlayerOnlyMessage
声明为抽象(带有空主体或引发异常,以提醒应在子类中重写该方法) 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.