我对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关闭时,它会发出编译器警告但会按照我的预期运行。
感谢任何帮助,以帮助我了解为什么会发生这种情况。
答案 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所说,computerPlayerOnlyMessage
是ComputerPlayer
类公开的方法,而不是它继承的类,所以即使编译器在ARC被禁用时报告警告,它也会是使用它的不良做法。
明确询问类实例是否实现了该方法,这是一种有效的解决方法。但是在我看来,解决方案缺乏良好的OO设计,除非我有充分的理由(有时它很方便),否则我不会使用它 - 在其他OO语言中,这是不可能的。
多态性允许使用类的实例,就好像它是其超类之一,但不是相反。您可以覆盖和专门化超类方法,但是您不能指望超类知道它的任何子类实现的方法。
我建议2种可能的解决方案:
computerPlayerOnlyMessage
类中的Player
声明为抽象(使用空体或抛出异常,提醒您应该在子类中覆盖该方法)computerPlayerOnlyMessage
移除ComputerPlayer
,改为覆盖playerMessage
。多亏了多态,无论您是以Player
还是ComputerPlayer
如果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协议,所以你可以调用所需的协议方法,让你通过他们的协议。
当我开始需要将行为“混入”各种对象时,协议开始最有意义。