Creating Tic-tac-toe in Swift: User interface

This blog post is the third and final update about my Tic-tac-toe game, written in Swift. The source code is available on GitHub:

https://github.com/ijoshsmith/swift-tic-tac-toe

The app now has a user interface, which allows you to play against the computer or against another person on the same iPhone.

tic-tac-toe

In my article about the Tic-tac-toe gameplay and data model I presented a diagram of domain components, such as the Game and GameBoard classes. The article about artificial intelligence reviewed a perfect-opponent strategy implementation. Now that the app has a user interface which ties these components together, we can see how they fit into the bigger picture.

tic-tac-toe-ui-diagram

The containment relationship between Game and GameBoard (i.e. a Game has a GameBoard) is mirrored by GameViewController and GameBoardView. When GameViewController begins a new game of Tic-tac-toe, it creates a GameBoard used as the data source for both a Game and GameBoardView.

GameViewController-startPlayingGame

The state of a game is visually depicted by GameBoardView. That UIView subclass relies on GameBoardRenderer and GameBoardLayout to perform drawing work.

GameBoardView-drawRect

As the code comments above indicate, creation of the layout and renderer objects is delayed until drawRect(_:) is called to ensure that the view’s graphics context and size are valid. Each object has two properties; one with an underscore prefix to store the object and another, without a prefix, that creates the object when necessary. This is similar to having a custom property accessor that uses an instance variable, in Objective-C.

The rendering work is performed by GameBoardRenderer:

GameBoardRenderer

All of the rendering routines are defined in a private class extension:

GameBoardRenderer-PrivateExt

This code might seem odd if you have experience with CoreGraphics, which is an API of C functions and structures. Thanks to Swift’s all-encompassing support for adding methods to types, I was able to create this wrapper API to hide the ugly details of using CGContext.

CGContextExtension

Rendering a user interface does not, and should not, involve determining the size and location of each thing in the user interface. This separate responsibility is often referred to as layout calculation. I separated these two responsibilities by having the renderer rely on GameBoardLayout for the size and location of every user interface element. The rendering methods seen above use these properties of a layout object:

GameBoardLayout

These properties are all lazy in order to avoid calculating their values more than once. This optimization is appropriate because a layout object is used multiple times throughout a game.

There is a lot more going on in this app, so if you’re interested be sure to clone the repository and dig in!

This entry was posted in Swift, Tic-tac-toe and tagged , . Bookmark the permalink.

1 Response to Creating Tic-tac-toe in Swift: User interface

  1. Pingback: Creating Tic-tac-toe in Swift: Artificial Intelligence | iJoshSmith

Comments are closed.