【问题标题】:Nested arrays in Objective-C ( NSMutableArray )Objective-C 中的嵌套数组 ( NSMutableArray )
【发布时间】:2009-08-07 13:56:20
【问题描述】:

我正在尝试构建一个嵌套数组:首先,我创建一个“PlayerItems”数组,该数组将包含 10 个数组,每个数组包含项目对象,对应于游戏中每个玩家的库存。在指示的行上,我收到以下错误:

错误:void 值没有被忽略,因为它应该被忽略

这里的 void 值是什么?如果我改用[[PlayerItems objectAtIndex:i] addObject:myitem],程序会编译但会崩溃。如果我将该行注释掉,它会编译并运行正常。感谢您的帮助!

self.PlayerItems = [[NSMutableArray alloc] initWithCapacity:11];
NSMutableArray *itemarray = [[NSMutableArray alloc] initWithCapacity:60];
item *myitem = [[item alloc] init];
item.kind = 1;
for (int i = 1; i < 10; i++) {
    itemarray = [[NSMutableArray alloc] initWithCapacity:60];
    [PlayerItems addObject:itemarray];
    for (int i2 = 1; i2 < 50; i2++) {
        myitem = [[item alloc] init];
        myitem.kind = 1;
        // The error occurs on the line below:
        ((NSMutableArray *) [[PlayerItems objectAtIndex:i] addObject:myitem]);
    }
}

【问题讨论】:

    标签: objective-c cocoa arrays nested nsmutablearray


    【解决方案1】:

    我会这样做:

    self.playerItems = [[NSMutableArray alloc] initWithCapacity:11];
    
    NSMutableArray * itemArray;
    Item * anItem;
    for (int playerIndex = 1; playerIndex <= 10; playerIndex++)
    {
        itemArray = [NSMutableArray arrayWithCapacity:60];
        [playerItems addObject:itemArray];
    
        for (int itemIndex = 1; itemIndex <= 50; itemIndex++)
        {
            anItem = [[Item alloc] init];
            anItem.kind = 1;
            [itemArray addObject:anItem];
            [anItem release];
        }
    }
    

    作为旁注,您绝对应该阅读memory management in Cocoa,因为您的原始代码充满了内存泄漏。一开始可能有点难以理解,但一旦你学会了它,它就会成为第二天性。值得努力。

    更新:

    更面向对象的方法是创建一个Player 类,并让每个Player 管理自己的一组项目:

    Player.h

    @interface Player : NSObject
    {
        NSMutableArray * items;
    }
    @property (readonly) NSMutableArray * items;
    @end
    

    Player.m

    #import "Player.h"
    @implementation Player
    
    @synthesize items;
    
    - (id)init
    {
        if ((self = [super init]) == nil) { return nil; }
    
        items = [[NSMutableArray alloc] initWithCapacity:60];
        Item * anItem;
        for (int itemIndex = 1; itemIndex <= 50; itemIndex++)
        {
            anItem = [[Item alloc] init];
            anItem.kind = 1;
            [items addObject:anItem];
            [anItem release];
        }
    
        return self;
    }
    
    - (void)dealloc
    {
        [items release];
        [super dealloc];
    }
    
    @end
    

    其他地方

    NSMutableArray * allPlayers = [[NSMutableArray alloc] initWithCapacity:11];
    
    Player * aPlayer;
    for (int playerIndex = 1; playerIndex <= 10; playerIndex++)
    {
        aPlayer = [[Player alloc] init];
        [allPlayers addObject:aPlayer];
        [aPlayer release];
    }
    
    ...
    
    [allPlayers release];
    

    【讨论】:

    • 第一种方法行得通,打算使用它!感谢 Player 对象的示例。对于复杂的项目(这个非常简单),面向对象似乎是要走的路。
    【解决方案2】:

    您好,我正在尝试构建一个嵌套数组……

    不要那样做。与 eJames 建议的真正的面向对象解决方案(即创建模型类的解决方案)相比,并行和嵌套数组更难读写。

    考虑设置每个玩家的第一个项目的项目类型的代码。使用并行/嵌套数组:

    for (NSArray *items in PlayerItems)
        [[items objectAtIndex:0U] setKind:newKind];
    

    使用模型对象:

    for (Player *player in players)
        [player setKind:newKind];
    

    哪个更清楚?

    维护并行和嵌套数组、使它们在每次更改时保持同步以及访问其中的任何项目所需的工作远远超过创建模型类所需的工作。此外,如果您决定移植到 Mac,没有模型类会严重伤害您,因为您不能使用绑定和实现 AppleScript 支持(我承认对游戏来说不是什么大不了的事)几乎是不可能的。

    正如 eJames 也提到的,您大量泄漏对象。按照他的建议阅读 Cocoa 的内存管理编程指南。

    正如 pgb 所说,Cocoa(和 C,就此而言)中的数组索引从 0 开始。此外,除非必须,否则通常不使用索引;请参阅上面的代码示例,以更清晰地迭代数组。

    正如 pgb 和 Christian 都指出的那样,addObject: 是返回 void 的方法,然后您将其转换为 NSMutableArray *。也许你打算把那个演员放在第一对方括号里?但如果你有一个真正的模型类,这是另一个你不会遇到的问题,因为你会立即设置新玩家的所有内容,包括他的物品:

    Player *player = [[Player alloc] init];
    
    //Set up name, SPECIAL stats, etc.
    
    for (int kind = 1; kind < 50; ++kind) {
        Item *item = [[Item alloc] init]; //I capitalized your class name for you.
        [item setKind:kind];
        [player addInventoryObject:item]; //Assume “inventory” is the name of the property that holds the player's items.
        [item release];
    }
    
    [allPlayers addObject:player];
    [player release];
    

    这给我带来了另一个建议:您可能还想为项目类型创建一个模型类,并在某个地方拥有一个数组。然后,每种类型都可以有一个名称、一个图标、也许是描述、性质(例如单手与双手)、职业要求、统计要求等,都在 item-kind 对象中。然后循环如下所示:

    for (ItemKind *kind in [self kindsOfItems]) {
        Item *item = [[Item alloc] initWithKind:kind];
        [player addInventoryObject:item];
        [item release];
    }
    

    此外,如果您设计的 kindsOfItems 属性可扩展,您可以允许玩家稍后通过插件 (Mac) 或应用内购买 (iPhone) 添加更多物品种类。

    【讨论】:

    • +1 来自我。我喜欢你对addInventoryItem 方法和ItemKind 类的想法。我希望 OP 已经为所有这些信息做好了准备 :)
    • 感谢您的回复。在这种情况下,我必须在单独的 player.m 文件中编写 addInventoryObject 吗?到目前为止,我一直在使用以下方法在 ProjectName.h 文件中创建类:@interface myclass : NSOBject{ int variable1; } @property(nonatomic) int variable1; @end 除了可重用性之外,在单独的文件中编写类是否有功能差异?
    • 它让事情变得更干净。它还使我能够为每个编辑器窗口创建一个类:我打开标题,然后点击 Counterpart (⌘⌥⇡) 以在同一窗口中加载实现,然后按 ⌘⌥⇠ 和 ⌘⌥⇢ 在标题和实现之间切换文件。
    • addInventoryObject:inventory 属性的可选访问器之一,您可以在 Player 的接口中声明(在 Player.h 中)并在实现中综合或编写访问器播放器(在 Player.m 中)。假设 inventory 是一个数组而不是一个集合,您必须根据实际的数组访问器来实现;具体来说,[self insertInventoryObject:newItem atIndex:[self countOfInventory]]。请参阅模型对象实施指南:developer.apple.com/documentation/Cocoa/Conceptual/ModelObjects
    【解决方案3】:

    Objective-C 中的数组是从零开始的,你的 for 循环从 1 开始。 你应该把它改成

    for (int i = 0; i < 10; i++)
    

    至于 void 错误,您不需要转换 addObject: 的返回值,因为它返回 void,这就是您收到警告的原因。

    那一行应该是:

    [[PlayerItems objectAtIndex:i] addObject:myitem];
    

    【讨论】:

    • 曾经有这样的行,但它在启动时崩溃(虽然编译得很好)。
    • 你确定它在这段特定的代码上崩溃了吗?还是以前?
    • 注释掉它并且运行良好,所以我假设它是那条线。
    【解决方案4】:

    在你调用的最后一行 addObject: 返回 void:

    - (void)addObject:(id)anObject
    

    然后您尝试将 void 转换为 NSMutableArray*。而且您也不会将铸造的 void 分配给任何东西。

    要将子数组添加到您的数组中,这就足够了:

    [[PlayerItems objectAtIndex:i] addObject:myitem];
    

    顺便说一句:您只创建了 9 个数组,并且只添加了 49 个子数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多