views:

2511

answers:

4

Hi, I'm trying to build a nested array: First, I make a "PlayerItems" array which will contain 10 arrays, each containing item objects, corresponding to the inventories of each player in the game. On the indicated line, I get the following error:

error: void valued not ignored as it ought to be

What is the void value here? If I used [[PlayerItems objectAtIndex:i] addObject:myitem] instead, the program compiles but crashes. If I comment that line out, it compiles and runs OK. Thank you for your help!

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]);
    }
}
+1  A: 

The arrays in Objective-C are zero based, and your for loop is starting in 1. You should change it to

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

As for the void error, you don't need to cast the return value of addObject: since it returns void, that's why you are getting the warning.

That line should read:

[[PlayerItems objectAtIndex:i] addObject:myitem];
pgb
Used to have the line like that, but it's crashing on startup (compiles fine though).
Are you sure it is crashing on this particular piece of code? Or is it before?
pgb
commenting it out and it runs fine, so i'm assuming it's that line.
+1  A: 

In the last line you're calling addObject: which returns void:

- (void)addObject:(id)anObject

You then try to cast void to NSMutableArray*. And you also don't assign the casted void to anything.

To add the subarray to your array this should be sufficient:

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

BTW: You're creating only 9 arrays and you're adding only 49 subarrays.

Christian
+5  A: 

I would do it as follows:

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];
    }
}

As a side note, you should definitely read up on memory management in Cocoa, since your original code is full of memory leaks. It can be a bit difficult to wrap your head around at first, but once you learn it, it becomes second nature. Well worth the effort.

update:

A more object-oriented way to do this would be to create a Player class, and have each Player manage its own set of items:

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

Elsewhere

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];
e.James
The first way worked, going to use that! Thanks for the example of Player objects.. for complicated projects (this one's pretty simple) object-oriented seems to be the way to go.
+5  A: 

Hi, I'm trying to build a nested array…

Don't do that. Parallel and nested arrays are harder to write and to read than real object-oriented solutions like the one eJames suggested, which is that of creating a model class.

Consider the code to set the item kind of every player's first item. With parallel/nested arrays:

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

With model objects:

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

Which one is clearer?

The work required to maintain parallel and nested arrays, to keep them all synchronized for every change and to access any item in them, is far greater than the work required to create a model class. Additionally, if you decide to port to the Mac, not having a model class actively hurts you, as you can't use Bindings and implementing AppleScript support (not such a big deal for a game, I admit) is next to impossible.

As eJames also mentioned, you are leaking objects profusely. Follow his recommendation and read the Memory Management Programming Guide for Cocoa.

As pgb said, array indexes in Cocoa (and C, for that matter) start at 0. Moreover, you generally don't use indexes unless you have to; see my code examples above for a much clearer way to iterate on an array.

As pgb and Christian both point out, addObject: is the method that returns void, which you then cast to NSMutableArray *. Perhaps you meant to put that cast inside the first pair of square-brackets? But this is another problem you wouldn't have if you had a real model class, as you would be setting up everything about the new Player at once, including his items:

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];

This brings me to one more suggestion: You might also want to make a model class for the item kinds, and have an array of those somewhere. Then, each kind can have a name, an icon, perhaps a description, nature such as one-handed vs. two-handed, class requirements, stat requirements, etc., all right there in the item-kind object. The loop then looks like this:

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

Additionally, if you design this kindsOfItems property extensibly, you can allow players to add more item kinds later, either through plug-ins (Mac) or in-app purchasing (iPhone).

Peter Hosey
+1 from me. I like your ideas for the `addInventoryItem` method and the `ItemKind` class. I hope the OP was ready for all of this information :)
e.James
Thanks for your response. In this case, I would have to write addInventoryObject in a seperate player.m file? So far I've been creating classes within the ProjectName.h file by using: @interface myclass : NSOBject{ int variable1; } @property(nonatomic) int variable1;@endIs there a functionality difference to writing classes in seperate files, besides reusability?
It keeps things cleaner. It also enables me to have one class per editor window: I open up the header, then hit Counterpart (⌘⌥⇡) to load the implementation in the same window, then ⌘⌥⇠ and ⌘⌥⇢ to switch between the header and implementation files.
Peter Hosey
`addInventoryObject:` is one of the optional accessors for the `inventory` property, which you would declare in the interface for Player (in Player.h) and synthesize or write the accessors for in the implementation for Player (in Player.m). Assuming that `inventory` is an array and not a set, you would have to implement in terms of actual array accessors; specifically, `[self insertInventoryObject:newItem atIndex:[self countOfInventory]]`. See the Model Object Implementation Guide: http://developer.apple.com/documentation/Cocoa/Conceptual/ModelObjects/
Peter Hosey