If you're organizing a pickup game of softball on the Fourth of July, then getting all the details right isn't a big deal because the game is most likely a one time thing among a group of friends more interested in having fun. Chances are people are not keeping stats. Although there is always that one guy...
But what if you are organizing all of Major League Baseball, 30 teams that each play 162 games over the course of a regular season? That takes some organization. Organization of schedules, of travel, of players, of stats, etc. And it's not just for one year, but for an uncertain number of years to come.
How do we organize that data? In computing, we model that data. What's a model? Good question.
According to Wikipedia, "A Data Model is an abstract model that organizes elements of data and standardizes how they relate to one another and to properties of the real world entities." For instance, a data model may specify that a data element representing a baseball team comprises a number of other elements which in turn represent the size of the roster, the size of the team budget, and the owner of the team to it.
To visualize this, I think of an Excel database. The name of our data model is the name of the database ("Baseball Team") and the names of the elements are the names of the columns and rows (roster size, team budget, team owner, etc).
Once we have our data model setup, we can run through large quantities of data or values much faster than we could if we did each one individually without a model. That is, in earnest, a general overview of data modeling which can get more complicated.
Question is, depending on what you're organizing, how do you want to organize your data? As we've discussed in previous posts, there are different ways to organize information in Xcode and with Swift. Enumerations are one way, structures (aka structs) and classes are others. In this post we'll focus on what structs are, when to use them, and what they do.
But what if you are organizing all of Major League Baseball, 30 teams that each play 162 games over the course of a regular season? That takes some organization. Organization of schedules, of travel, of players, of stats, etc. And it's not just for one year, but for an uncertain number of years to come.
How do we organize that data? In computing, we model that data. What's a model? Good question.
According to Wikipedia, "A Data Model is an abstract model that organizes elements of data and standardizes how they relate to one another and to properties of the real world entities." For instance, a data model may specify that a data element representing a baseball team comprises a number of other elements which in turn represent the size of the roster, the size of the team budget, and the owner of the team to it.
To visualize this, I think of an Excel database. The name of our data model is the name of the database ("Baseball Team") and the names of the elements are the names of the columns and rows (roster size, team budget, team owner, etc).
Once we have our data model setup, we can run through large quantities of data or values much faster than we could if we did each one individually without a model. That is, in earnest, a general overview of data modeling which can get more complicated.
Question is, depending on what you're organizing, how do you want to organize your data? As we've discussed in previous posts, there are different ways to organize information in Xcode and with Swift. Enumerations are one way, structures (aka structs) and classes are others. In this post we'll focus on what structs are, when to use them, and what they do.
What is a struct?
According to the Big Nerd Ranch's guide to Swift Programming, "A struct is a type that groups a set of related chunks of data together in memory. You use structs when you would like to group data together under a common type."
So let's break that down.
We've seen types before, usually strings, integers, and doubles or floating point types. In this case, a struct is a custom type that you can create to fit your needs as you create and organize information. In our case, we're going to create a Hitter struct that keeps tract of the number of hits and homers that a players has. We will organize information according to these custom parameters.
Unlike previous posts that we have written and executed in Xcode Playgrounds, this time we will need to create an Xcode project to properly play with structs. Why can't we use structs in a Playground?
The main reason we need to create a whole new project rather than use a playground is that we write structs in one file, typically an ancillary file, and then call those structs from another file, usually the main file, that our code exists in. Projects allow us to create and access multiple files: Playgrounds do not.
Why can't we just put them all in one file? If we did, when it came time for the computer to run our program it would run everything, not just what it needed that instant and this would take longer to run. By putting some important information in a separate file we keep our program faster, leaner, and more efficient.
When to use a struct?
When to use a struct?
We wouldn't need a struct to publish the fact that Didi Gregorious had 155 hits and 20 homers in 2016 because it's just one line that we can write out rather quickly ourselves. But what if we build a site that listed the names of all the players in baseball and how many hits and homers each hitter had? Considering that there are over 600 hitters in Major League Baseball every year, it would take a long time to write those all out. This is where structs and their data models come in.
What can structs do?
According to Apple's own documentation, structs can do the following:
In this case, we want to see index number 3 which returns 22 wins so we write stewartWins[3]. We can do the same thing with dictionaries as seen in the second example above.
An Example of a Baseball Struct
OK. So let's create a new Xcode project and our own struct.
Open Xcode and double-click on "Create a New Xcode Project". Choose macOS as your template and for this project choose "Command Line Tool" before clicking "Next". Give your project a name such as, hitterStruct, and make sure that the language is set to Swift before hitting "Next". Then choose where you want to save your work. It can be in a specific folder, on your desktop, or wherever else you want; hit "Create".
Xcode will then open. On the far left panel click on the "main.swift" file which will open in the center panel with some sample code in it some of which we'll remove in a minute.
Create a new file (File > New > File) and name it hitter. It will save under the main.swift file in the far left panel as hitter.swift. Enter the hitter.swift file by clicking on it.
Under "import Foundation" let's create our struct and define what properties it will have.
In this case, let's look at the career numbers, through the 2016 season, for Mookie Betts.
What can structs do?
According to Apple's own documentation, structs can do the following:
- Define properties to store values
- Define methods to provide functionality
- Define subscripts to provide access to their values using subscript syntax
- Define initializers to set up their initial state
- Be extended to expand their functionality beyond a default implementation
- Conform to protocols to provide standard functionality of a certain kind
Sounds great, right? Now what does that all mean? Let's break those down because they will also be true of classes.
- Define properties to store values: If you define a property such a hits, then you can give that property a value such as 200 hits. And once something has a value, you can use that value. If you don't define hits, then you can't give it a value and you can't use that value.
- Define methods to provide functionality: Once you have your properties such as hits and homers, you can create a method, say, a method that calculates what percentage of a hitter's hits are homers, by defining a method that calculates that figure. This is what I meant in the previous paragraph when I said once a property has a value then you can use it. This is an example of us using that value to calculate something else.
- Define subscripts to provide access to their values using subscript syntax: According to Apple's documentation, subscripts "are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval."
- For example, we can create an array called stewartWins that contains the total number of wins Dave Stewart had in some of his years as a starting pitcher and then access specific elements in the stewartWins
Array
by selecting an instance by choosing its appropriate index number.
In this case, we want to see index number 3 which returns 22 wins so we write stewartWins[3]. We can do the same thing with dictionaries as seen in the second example above.
- Define initializers to set up their initial state: Can you imagine a hitter coming to bat without wearing a number on the back of his jersey? That's like variables or constants not being initialized with values. There are times when it's OK for variables and constants to not be initialized, but it's also nice to have the option to initialize them which structs support.
- Be extended to expand their functionality beyond a default implementation: In other words, structs are not static or set in stone, but have the flexibility to expand their initial functionality. In baseball-ese that means you might come into the league knowing how to throw a fastball and curveball, but you can always pick up a change and a knuckle-curve: You aren't restricted to just what you had on day one.
- Conform to protocols to provide standard functionality of a certain kind: While this is a little vague, it's another way of saying that structs, in general, play by standard protocol rules. In baseball-ese, structs will be around the strike zone - they won't kill anyone or your program.
An Example of a Baseball Struct
OK. So let's create a new Xcode project and our own struct.
Open Xcode and double-click on "Create a New Xcode Project". Choose macOS as your template and for this project choose "Command Line Tool" before clicking "Next". Give your project a name such as, hitterStruct, and make sure that the language is set to Swift before hitting "Next". Then choose where you want to save your work. It can be in a specific folder, on your desktop, or wherever else you want; hit "Create".
Xcode will then open. On the far left panel click on the "main.swift" file which will open in the center panel with some sample code in it some of which we'll remove in a minute.
Create a new file (File > New > File) and name it hitter. It will save under the main.swift file in the far left panel as hitter.swift. Enter the hitter.swift file by clicking on it.
Under "import Foundation" let's create our struct and define what properties it will have.
In this case, let's look at the career numbers, through the 2016 season, for Mookie Betts.
What do we have here? First, we created a struct with the struct keyword. We then gave our struct a name, in this case, Hitter which is capitalized. That's important. Then we open up a curly bracket to define our properties. The properties are all variables, one for the player's name (name), hits, and homers.
In this case, we've initialized our variables by giving them values ("Betts", 443, 54).
Now let's create a function so we can do something with our struct. Let's have ours say, "Betts has 443 hits and 54 homers."
Using the func keyword we create a new function which we call printHitterDescription. We add the () in case we want to pass an argument later. We'll leave it empty for now as we have no need to pass any arguments. And then we open up a set of curly brackets within which we'll write our function.
In this case, our function is an example of string interpolation, a quick way to show what structs can do. print() is a function within the printHitterDescription function that will print whatever we write in the parentheses to Xcode's console, below and to the right of the center section. Here, we want it to say, "Betts has 443 hits and 54 homers." We plug in our properties on line 17 (name, hits, homers) where we need them so the values will print out.
Now that the struct is ready to go, we need to connect the main.swift file to the hitter.swift file so it can pull the data it needs to complete the printHitterDescription function. We connect the two files by calling the hitter.swift file from the main.swift file. Here's what that looks like:
See line 11? That's where we call the Hitter struct from the hitter.swift file. In this case, we call it by setting Hitter() to the myHitter variable.
Line 12 prints out our "Betts has 443 hits and 54 homers" statement to the console by running our printHitterDescription() function on the variable myHitter that calls the Hitter file.
That's what it looks like to run a single instance through a model. In a future post we'll run more data through it so you can how that works.
On Deck: Classes and how Structs and Classes are similar and different
In this case, we've initialized our variables by giving them values ("Betts", 443, 54).
Now let's create a function so we can do something with our struct. Let's have ours say, "Betts has 443 hits and 54 homers."
Using the func keyword we create a new function which we call printHitterDescription. We add the () in case we want to pass an argument later. We'll leave it empty for now as we have no need to pass any arguments. And then we open up a set of curly brackets within which we'll write our function.
In this case, our function is an example of string interpolation, a quick way to show what structs can do. print() is a function within the printHitterDescription function that will print whatever we write in the parentheses to Xcode's console, below and to the right of the center section. Here, we want it to say, "Betts has 443 hits and 54 homers." We plug in our properties on line 17 (name, hits, homers) where we need them so the values will print out.
Now that the struct is ready to go, we need to connect the main.swift file to the hitter.swift file so it can pull the data it needs to complete the printHitterDescription function. We connect the two files by calling the hitter.swift file from the main.swift file. Here's what that looks like:
See line 11? That's where we call the Hitter struct from the hitter.swift file. In this case, we call it by setting Hitter() to the myHitter variable.
Line 12 prints out our "Betts has 443 hits and 54 homers" statement to the console by running our printHitterDescription() function on the variable myHitter that calls the Hitter file.
That's what it looks like to run a single instance through a model. In a future post we'll run more data through it so you can how that works.
Challenge: Create a new project with two Swift files one of which contains a struct for pitchers that models pitcher names, games started, and quality starts and then Tweet it to me at @randallmardus.
On Deck: Classes and how Structs and Classes are similar and different
No comments:
Post a Comment