However XCode is saying that I cannot use objectAtIndex & removeObjectAtIndex on this new array, …
No, it's saying that you aren't trying to use it on an array.
What you are trying to use it on is a DeckOfCards:
DeckOfCards *newDeck = [[DeckOfCards alloc] init];
int r = arc4random() % 52;
NSLog (@"The card you picked is: %@, and there are %i cards left", [newDeck objectAtIndex:r], [newDeck count]);
[newDeck removeObjectAtIndex:r];
newDeck
being the DeckOfCards
that you created on the first line.
A DeckOfCards
is not an array:
@interface DeckOfCards : NSObject
A DeckOfCards
is simply an object. Not just any object; you have added things to it (the deckOfCards
and pickACard
methods). But it is not an array, and so does not respond to objectAtIndex:
and is not a mutable array and so does not respond to removeObjectAtIndex:
, either.
So where do you have an array? Well, you create one in your deckOfCards
method:
-(void)deckOfCards
{
NSMutableArray *deckOfCards = [NSMutableArray arrayWithObjects:
@"One of Hearts", @"Two of Hearts"..., nil];
}
But what happens to that array?
Nothing. You create it, and then you drop it on the floor. You aren't returning it to whatever called you; indeed, you can't, since this method returns void
.
Momentarily leaving aside the architectural issues, which can be forgiven assuming that you are very new to programming, you need to do several things:
- Change the declaration of
deckOfCards
method to declare that it will return an NSMutableArray *
, not void
.
Add a line immediately after the creation of the array that returns the array:
return deckOfCards;
(And note that deckOfCards
here refers to the array*.)
Change pickACard
to call deckOfCards
. That will create the array and (once you've made change #2) return it to you. Declare a variable in pickACard
, similar to the one you declared in deckOfCards
, and assign the result to deckOfCards
to it.
- Now that you have an array in
pickACard
, you can attempt to retrieve one of its items, log it, and remove it. Do this by sending the objectAtIndex:
and removeObjectAtIndex:
messages to the array, not to the object that isn't an array.
- While you're at it, correct the type of
r
. NSArray indexes are of type NSUInteger
, not int
.
Now the program should compile, run, and almost work.
Almost? Well, you have one more thing to do.
deckOfCards
creates a fresh deck every time; you remove a single card from that deck, but then forget all about that deck, and will be using another fresh deck the next time through.
This is your next challenge: Change the program to create a deck in initialization, and remember and reuse that deck for each subsequent draw. Be sure to handle the case of deck exhaustion (no more cards) correctly, probably by creating a fresh deck at that moment.
(Your first instinct will be to copy and paste. Do that as a first draft only. Then change it so that the deck-creation code is in only one place, a method for that purpose, and you call that method from both places where you need to create a fresh deck.)
I'll give you a hint: Instance variable.
*In your deckOfCards
method, you'll see two things named deckOfCards
: That method, and the array you declare within it. Two different things with the same name. The compiler doesn't care; methods and variables exist in separate namespaces, so it has no problem knowing which is which at any given moment. But you should probably change one or the other to aid your own understanding, not to mention others' suggestions of what to change (“do this with deckOfCards
”, I say—but which deckOfCards
do I mean?).
I suggest renaming the array variable. Just naming it array
will do for a start. (But only as long as it's a local variable, declared within that method.)
When you make it an instance variable, change the name back to something more specific. _deckOfCards
is the common naming convention nowadays—the underscore tells you (again, the compiler doesn't care) that this name is the name of an instance variable.
DeckOfCards*
? – KennyTM Sep 1 '12 at 16:01