Card War: The Data Model & Linking the UI to Code

Free iOS Development Tutorial

Dive into iOS development with this comprehensive guide that covers topics such as connecting the UI to the View Controller, adding card and deck classes, and implementing shuffle functionality.

This exercise is excerpted from Noble Desktop’s past app development training materials and is compatible with iOS updates through 2021. To learn current skills in web development, check out our coding bootcamps in NYC and live online.

Topics Covered in This IOS Development Tutorial:

Connecting the UI to the View Controller, Modeling a Single Card by Adding a Card Class, Modeling All the Cards by Adding a Deck Class, Adding the Shuffle Functionality

Exercise Overview

In this exercise, we’ll finish up our UI by connecting each element to the code, so we can refer to these elements in our View Controller. Additionally, we’ll create the data model that will define properties and methods for both our deck and our cards.

Getting Started

  1. Launch Xcode if it isn’t already open.

  2. If you completed the previous exercise, Card War.xcodeproj should still be open. If you closed it, re-open it now.

  3. We suggest you complete the previous exercise (5A) before doing this one. If you did not do the previous exercise, complete the following:

    • Go to File > Open.
    • Navigate to Desktop > Class Files > yourname-iOS App Dev 1 Class > Card War Ready for Data Model and double–click on Card War.xcodeproj.
Full-Stack Web Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.

Connecting the UI to the View Controller

We can refer to these elements in our app, let’s add outlet or action connections to link up the visuals with the View Controller.

  1. In the Project navigator, make sure Main is selected.

  2. Go to the top right and click the Adjust Editor Options icon assistant editor icon and choose the Assistant option.

    ViewController.swift should appear to the right of the Storyboard.

  3. If you need to hide some of Xcode’s interface to make room on-screen, feel free to go to the top right and click one or both the Hide or show the Navigator show hide navigator icon and Utilities show hide utilities icon buttons. Do not hide the Document Outline!

  4. In the View Controller on the right, delete everything inside class ViewController’s curly braces so it is empty:

    class ViewController: UIViewController {
    
    }
  5. Let’s first link the card back button to the code. In the Storyboard, make sure the button under the word Deck is visible. Then hold the Control key (or the Right mouse button) and drag from the Deck button to the View Controller. Release once you see the blue connector line under this line of code:

    class ViewController: UIViewController {
  6. In the prompt that appears, set the following:

    Name: deckButton (Remember to pay attention to uppercase vs. lowercase!)
    Type: UIButton
    Storage: Weak
  7. To apply the connection, click Connect (or press Return).

    We’ve got our first outlet! We’ll eventually use this deckButton variable to change the image when the game ends and there are no more cards in our virtual deck.

  8. We need to keep track of each player’s score so whenever a player wins a round, their score number increments up. So one at a time, we’ll need to drag from a zero. To make sure we don’t accidentally make a connection for the wrong label, go to the Storyboard and in the Document Outline nested under superView, select the top 0.

  9. Hold Control (or the Right mouse button) and drag from the top 0 to the View Controller, releasing once you see the blue line under the following:

    @IBOutlet weak var deckButton: UIButton!
  10. In the prompt that appears, set Name to player1ScoreLabel and click Connect.

  11. Rinse and repeat for the bottom 0. Once again, it will be easiest to drag from the Document Outline instead of the Editor. Release the mouse when the blue line is between the most recent line of code and the final curly brace.

  12. In the prompt, set Name to player2ScoreLabel and press Return.

    Whenever the user clicks either the deck button or restart button, our app will need to execute some logic. That means we’ll need to create an action for these two. (We’ll just create them now, and flesh them out in another exercise.)

  13. In the Storyboard, hold the Control key (or the Right mouse button) and drag from the Deck button to the View Controller underneath this line of code:

    @IBOutlet weak var player2ScoreLabel: UILabel!
  14. In the prompt that appears, set the following:

    Connection: Action (don’t forget this setting!)
    Name: drawCards
    Type: Any

    Click Connect (or press Return).

  15. In the Storyboard, hold Control (or the Right mouse button) and drag from the Restart button to the View Controller. Release the mouse once the blue connector line is underneath the previous function, but within the ViewController class’ final curly bracket.

  16. In the prompt that appears, create another action as follows:

    Connection: Action
    Name: restartButton
    Type: Any

    Click Connect (or press Return).

  17. Make sure your code looks like this (feel free to add any additional spacing, as we did to enhance readability):

    class ViewController: UIViewController {
    
       @IBOutlet weak var deckButton: UIButton!
       @IBOutlet weak var player1ScoreLabel: UILabel!
       @IBOutlet weak var player2ScoreLabel: UILabel!
    
       @IBAction func drawCards(_ sender: Any) {
    
       }
    
       @IBAction func restartButton(_ sender: Any) {
    
       }
    
    }

    We’re done with the UI, so let’s get to coding! We’ll start by modeling our data.

Creating the Data Model Swift File

  1. In the Project navigator, select the Card War folder so that the file is added inside.

  2. Go to File > New > File or use the shortcut Cmd–N.

  3. Under iOS and Source, double–click on the Swift File template.

  4. Next to Save As, type: Data Model.swift

  5. Navigate to Desktop > Class Files > yourname-iOS App Dev 1 Class > Card War (or Card War Ready for Data Model) > Card War.

  6. Click Create.

  7. If you previously hid the Project navigator on the left, go to the top right and click the Hide or show the Navigator button show hide navigator icon to make it reappear.

    Notice that Data Model.swift was created. (If it is not currently selected, click on it to open it in the Editor.)

  8. Also near the top right, click the Show the Standard editor icon standard editor icon so the files are no longer displayed side-by-side.

  9. We will model the properties and methods for our cards and deck in this new file. When you’re learning how to model data, it can be helpful to see a visual reference of the objects you will be creating a template for. To open an image in a new tab:

    • Press Cmd–T to open a new tab.
    • With the new tab active, go to the Project navigator and click on the Assets.xcassets folder.
    • Click on Deck near the bottom.
    • Select the 1x deck image in the right column and press Spacebar so we can take a closer look at the visual representation of all of our cards.
  10. Take note of the unique properties of our cards (we’ll need to model these):

    • Each card has a different image and has a different letter or number.
    • Each row of cards is a different suit: Hearts, Diamonds, Clubs, and Spades.
    • Within each row, the cards are displayed in order of their value (starting with the lowly 2 and ending with the omnipotent Ace).
  11. Press Spacebar again once you’re done previewing the deck image.

Modeling a Single Card by Adding a Card Class

  1. Near the top of Xcode, click on the Data Model.swift tab to switch to this file.

  2. In order to display cards in our UI, we need to use Apple’s provided UIImage class. It’s part of UIKit, so we need to import that. Change the import line as shown:

    import UIKit
  3. We’ll need a Card class to model each card. (Remember that we use UpperCamelCase for class names.) Add the bold code shown below:

    import UIKit
    
    class Card {
    
    }

    Ignore the red error red alert icon for now. We’ll be adding the initializer to fix this shortly.

  4. Let’s start adding properties to the Card class. Add an image property:

    class Card {
    
       var image: UIImage
    
    }
  5. The suit property will be a set of special characters that will represent each of the four suits. We’ll see how to add these characters shortly. For now, set the suit property to a String value as shown below:

    var image: UIImage
       var suit: String
    
    }
  6. Add a rank property that takes a String value as shown in bold:

    var image: UIImage
    var suit: String
    var rank: String

    This property represents the letter or number on the card. We are using the String data type because the value can be either a number between 2 and 10, or one of the letters: J, Q, K, or A.

  7. Add one final property to the class as shown:

    var image: UIImage
    var suit: String
    var rank: String
    var value: Int

    The value property models what the card’s letter or number means in terms of its value. For instance, a 2 card will have the lowest value of 2, and an Ace will have the highest value—13. These are all whole numbers, so we’re using the integer type.

  8. Now that we’ve created our four properties, we need to create an initializer. As shown below, add the following bold initializer that will take the three parameters for suit, rank, and value, and assign the properties for each:

    var value: Int
    
       init(suit: String, rank: String, value: Int) {
          self.suit = suit
          self.rank = rank
          self.value = value
       }
    
    }

    We are using the self instance to refer the variables to the parameters that are passed into the initializer.

  9. Hmm, we still have a red error red alert icon. Click on it to see that we still haven’t initialized all the properties. But how do we initialize the image?

  10. Take a look through the Assets.xcassets folder to see that each card has its own file. They are all named using the same format: the suit (using the emoji character that represents the suit’s symbol), followed by the rank (2–A).

    NOTE: Emoji characters are accessed from the Edit menu when typing the filename.

  11. Back in our Data Model code, initialize the image so the card loads its own image. When a card is given a suit and rank, it will create its own string interpolation and load a UIImage with the exact same name:

    init(suit: String, rank: String, value: Int) {
       self.suit = suit
       self.rank = rank
       self.value = value
       image = UIImage(named: "\(suit)\(rank)")!
    }

    The image does not need a self instance, as we did not specify it in the initializer.

Modeling All the Cards by Adding a Deck Class

  1. To define the attributes and behaviors of the entire deck of 52 cards, let’s create another class. Above the Card class block of code, add the Deck class as shown:

    import UIKit
    
    class Deck {
    
    }
    
    class Card {
  2. Let’s create a deck variable that will contain an array of the Card class. Type the following (you will see a red error—we’ll make it disappear in the next step):

    class Deck {
    
       private var deck: [Card] = {
    
       }()
    
    }

    The deck array is initialized with a closure (indicated by the curly braces {}). Keep in mind that if a function does not take any parameters, we indicate this using empty parentheses (). We’ll explain why the deck variable is private later in this exercise.

  3. We’ll generate the card deck to fill up the array over the next few steps, but for now, let’s simply get rid of the red error. Type the following bold code:

    private var deck: [Card] = {
       var cards = [Card]()
    
       return cards
    }()

    Upon initialization, we want the private deck variable to receive the contents of the cards array once it’s filled. For this reason, we want to return the cards variable.

  4. To start filling up our deck with cards, we first need to know which suits to add. Let’s create an array containing the four suit characters. Set up the array as follows:

    var cards = [Card]()
    var suits = ["", "", "", ""]
    
    return cards
  5. We need to insert emoji characters into this array. Go to Edit > Emoji & Symbols.

  6. The window that appears allows you to insert emoji or other special characters. It can be expanded or contracted, depending on your preference. You can only drag a character when using the expanded version, so let’s make sure we’re all seeing the same thing.

    Look at the top of the window. If it doesn’t say Characters, go to the top right and click the expand contract special chars window button to expand it.

  7. At the top right of the window, click into the search field and type: suit

  8. We want to use the four suit symbols beginning with the left spade selected in the screenshot below:

    insert emoji character

  9. With Xcode still visible, drag in one of each of the four suit characters to fill the suits array as shown:

    suit characters code

    Close the window of special characters when done.

  10. Next, we’ll add another array of all 13 different ranks. Type the following:

    var ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
  11. To generate all 52 of the cards, we’ll need to iterate through both of the arrays we just added using two for loops. (The second one will be nested inside the first.) First we need to iterate through the suits array. Add the beginning of its loop as follows:

    var ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
    for suit in suits {
    
    }
    return cards
  12. Every time we start with a new suit, we want to reset the card value to 1. Add the bold code shown below:

    for suit in suits {
       var value = 1
    }
  13. Now that we have all of our suits present, we need to iterate through the ranks array. Let’s nest a new loop within the suits loop as follows:

    var value = 1
    for rank in ranks {
       cards.append(Card(suit: suit, rank: rank, value: value))
       value += 1
    }
    return cards

    This loop is increasing the value by 1 each time. To generate the cards, we are calling the main initializer of the Card class, and giving each card a suit, rank, and value. The card will load its own image based on these, and append the generated card to the deck array, which will hold all the cards in order!

Adding the Shuffle Functionality

To make our game interesting (not to mention playable), we need to shuffle the deck so they’re not always in the same order! We need our Deck class to take the ordered deck we just modeled and use that to create a new, randomized deck.

  1. At the top of the Deck class, add a variable called shuffledDeck:

    class Deck {
    
       var shuffledDeck = [Card]()
    
       private var deck: [Card] = {

    We made this variable public because it will be used by the ViewController (which you’ll see in the next exercise). We are setting it to an empty array.

  2. We need to populate the empty array with cards that are shuffled in a random order. At the bottom of the Deck class, start creating a function that shuffles the cards:

    return cards
    }()
    
    func shuffle() {
    
    }
  3. Inside the function we’ll generate a new deck, which is a copy of the original deck:

    func shuffle() {
       var newDeck = deck
    }

    Earlier, we set the original deck variable to private. This ensures that only our newDeck is used to generate the random shuffledDeck.

  4. Add the variable that will keep a count of the remaining cards:

    func shuffle() {
       var newDeck = deck
       var remainingCards: UInt32 = 52
    }

    NOTE: We’ve set the variable to the UInt32 data type (an unsigned integer) as it’s required by the arc4random_uniform function we’ll use to pick random cards.

  5. We need to reset the card deck each time, in case this isn’t the first time we shuffle the cards. Remove all cards in the shuffledDeck by adding the following code:

    var remainingCards: UInt32 = 52
       shuffledDeck.removeAll()
    }
  6. Now that shuffledDeck is empty, we’ll use a repeat loop (similar to a while loop) to add the shuffled cards from newDeck, until no remaining cards are left. Add the following:

    shuffledDeck.removeAll()
    repeat {
    
    } while remainingCards > 0

    NOTE: A repeat-while statement allows a block of code to be executed as long as the condition remains true. The code we added says to repeat an action as long as the remainingCards variable is greater than 0 (meaning we aren’t done seeding our randomized deck with cards).

  7. Add the following code to tell the loop to pick random cards from the new copy of the deck, and then add them into the shuffledDeck, one at a time:

    repeat {
       let cardToPick = arc4random_uniform(remainingCards)
       shuffledDeck.append(newDeck.remove(at: Int(cardToPick)))
       remainingCards -= 1
    } while remainingCards > 0

    By reducing the number of remainingCards each time the randomized cardToPick has been removed from the newDeck and placed into the shuffledDeck, we eventually end up with 0 cards. Once that happens, our shuffledDeck is ready for action, and the repeat-while loop terminates.

  8. Lastly, we need to add a shuffle initializer to the deck. Above the shuffle function, add the following bold code:

    return cards
    }()
    
    init() { shuffle() }
    
    func shuffle() {

    To sum up our data model, when we create an instance of the Deck class, it calls the shuffle method. The shuffle method picks random cards from the deck and generates the shuffledDeck array. Because of this, we don’t need to initialize any properties as shuffledDeck is implicitly initialized to the empty array of cards. The initializer we just added calls the shuffle method, so that shuffledDeck loads and is ready to work!

  9. Save the file and keep Xcode open so that we can continue with this file in the next exercise.

Noble Desktop Publishing Team

The Noble Desktop Publishing Team includes writers, editors, instructors, and industry experts who collaborate to publish up-to-date content on today's top skills and software. From career guides to software tutorials to introductory video courses, Noble aims to produce relevant learning resources for people interested in coding, design, data, marketing, and other in-demand professions.

More articles by Noble Desktop Publishing Team

How to Learn IOS & Web Development

Master IOS Development, Web Development, Coding, and More with Hands-on Training. IOS Development Involves Designing Apps for Apple Mobile Devices with Tools Like Xcode and SwiftUI.

Yelp Facebook LinkedIn YouTube Twitter Instagram