Since Objective-C doesn't have class variables per-se (they're merely simulated using static variables), child classes can only directly access the static globals if you define the method in the same source file/compilation unit. This breaks other best practices (one class definition per compilation unit). The usual approach to access class fields is to use accessors.
In this case, be careful you don't couple the classes too tightly. Passing the board (as an object, not an array) to the Player
(Person
might be a better name, as a computer is also a player) and Computer
, whether as a method parameter or a property, is more flexible than referring to a global or to a static member of another class. The player objects decide where to place, then tell the board where to place the piece. Alternatively, the game passes a read-only version of the board to a player; the player's placement method returns where to place a piece. For one thing, decoupling and using a board object can prevent cheating. Imagine someone injects their own Player class which lets them place multiple pieces on their turn. For another, the indirection it makes it easier to add network support (messages between objects become network messages in a process that is transparent to the local objects).
Think also about where the players are created. It might make more sense to have something else create the players and pass them to the startGame
method. This would make sense if the players were competing in a tournament, for example, and the player objects thus needed to exist for longer than a single game.
Class composition refers to one object having another as a member. C, for example, didn't support inheritance, but let you nest structs. Another way of saying this is that class composition is about "has-a" relationships, while inheritance is about "is-a" relationships. The player classes, for example, could have a pointer to the board, which each uses to place pieces.
Objective-C also doesn't have pass-by-reference. Instead, it uses pointers.
Also, make sure your game handles ties. You might want to simplify the game loop to accomplish this. In pseudocode,
// nextPlayer returns 'nil' if game is over (win or tie)
while currPlayer := [game nextPlayer]:
// player will tell board where to place piece
[currPlayer move]
Or:
// nextPlayer always returns a valid player
while currPlayer := [game nextPlayer]:
// player's method returns what and where to place
[self place:[currPlayer move] for:currPlayer]
// explicitly test for game end, which includes wins & ties
if [game isOver]:
break