簡體   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