Like most other object-oriented languages, Swift allows you to create new datatypes to model application functionality or the real world. The most basic way to begin to create a new datatype is an enumeration. In this lesson, I'll show you how to define a custom enumeration.
1.Introduction3 lessons, 15:05
2.Foundational Concepts5 lessons, 43:51
3.Working With Collections3 lessons, 26:26
4.Controlling Flow7 lessons, 1:22:24
5.Functions5 lessons, 51:54
6.Creating Types6 lessons, 1:08:10
7.Conclusion1 lesson, 01:15
To this point the course, we've covered a lot of information. We've talked about built in types, we've talked about working with functions, we've talked about controlling the flow of your application. And all of those things are going to get you far enough to be able to write applications with the Swift programming language. Now, eventually along the way, you're going to want to be able to deal with custom types. You want to be able to create your own types of data. So, maybe I don't want to deal with or continue to have to work with just a plain old integer type now. Maybe I want to create a specialized version of an integer or some other sort of type that's going to represent data that I need for my particular application. And in order to understand how to do that we're gonna break this up into several pieces or several lessons within the section. And in this lesson, we're going to start with the most basic. In terms of custom types, the most basic one that we can start to deal with is any numeration, or an enum. So what exactly is that? Well, the numeration is really nothing more than a way to group together related values that really allows you to work with those in a type safe way in your code. Now we've kind of looked at enumerations a little bit previously, when we started to talk about exceptions and error handlings, when we were dealing with a whole error type concept. And we created an enumeration that was going to represent that value. And that's just one way to use an enumeration. Now we want to look into creating different types of enumerations. So let's see what the syntax of creating an enumeration looks like. Just like before, we're going to use the enum keyword. And then we're gonna specify a name. And this name could be anything, we could just call it MyEnum. And then we have open and closed parenthesis and then we specify the body, and then within the body we can do a number of different things. But the most basic thing we can do is define a number of different values, that are denoted by a case statement. So I could say case Value1, case Value2. And so on, and so forth, and then throughout my code I can refer to these different values within my custom enumeration by referencing MyEnum. And then I can talk about Value1 and Value2. Now, this is a very simplistic example but it really serves a point. So I can create a special type called whatever I would like, in this case MyEnum that has certain values in it. Now, enumerations are a little bit limited, because this is really all that they do. They will contain certain values that you can refer to, like I said, in a type safe way. But it does get a little bit more complicated, and we can start to do some more custom things. So let's look at a very quick example. So let's say I created an enumeration. And we wanted to have an enumeration to represent a certain concept out in the world. And we're going to say direction. So we have a direction enumeration. And we have four different cases here. We have a North. We have a South. We have an East. And then we also have a West. But just to show you the flexibility of this is I don't necessarily have to put all of these on their own case statement. I can use a comma to separate them. So I could put East and West on the same line separated by a comma, and then I could go into direction and I could still refer to them all individually, North, South, East and West. So that's pretty nice. So I've created this enumeration that I can now use in my code to be able to do some sort of logic. So let's say at some point along the way I needed to assign a particular enumeration value to a variable or a constant or what have you. So in this case, I could simply say var dir is gonna be equal to direction.east. And so now everywhere else that I go, the direction, the dir variable, is gonna contain a direction that just so happens at this point to be direction.east. Now, the nice part about this is that once I have defined this and that swift in the compiler know that dir is actually a direction type. If I wanted to change this again I could say dir is gonna to be equal to and I could save myself the hassle of having to write direction again by using the shorthand notation of just using dot, and then I can specify North, South, East, and West. And this is done because at this point, like I said, the compiler and swift already know that dir is of type direction. Now the same thing would work here is if I were to come in here and say that dir is of type direction. And then, later on during my assignment statement, I can once again do the same thing so I don't necessarily have to initialize it and then implicitly declare that variable or that constant. I could do it explicitly, and then from everywhere else that I refer to that dir variable, I could simply use this shorthand notation, which is pretty nice. And the other nice thing about that is when I start to assign a particular value to this variable or this constant. Then by just by looking at this, because it uses the dot notation which is required, so I can't just say East because it won't know what East is, I have to use the dot East. Then just by looking this, I am going to know that that particular value associated with this variable is actually a numerated type. So that's kind of nice. There's some other interesting places where these enumerations are going to be useful, and one of those is going to be within a switch statement. So let's say I created a direction and I set it equal to a direction.north. Now at some point in my code I had maybe have a switch statement and I want to Switch on that dir variable. So then, I can go in here and start to write some case statements to describe what I want to match against, and then the logic and the functionality that I want associated with that particular direction. So I could use my case statement. And then I will be able to use that shorthand notation again. I will be able to say .North. And then I could come in and say print you are going north. And I could do this for all the other cases just like we've done before. But then at the very end I could also put a default, if I wanted to and maybe just print I don't know where you are going. So I could go ahead and save this, and if I were to run this application at this point, because dir contains North, it's going to match on that first case statement. And it's going to put print out, you are going north. Now, of course, I could put anything else in here and it would miss this particular case and just print, I don't know where you are going. So I could change this to be east and if I were to run again, you'll see that I don't know where you are going. So once again, we can use this nice matching feature of the Swift programming language to be able to match against different enumerated values. Now another interesting feature of enumerations within the Swift programming language that may be a little bit different than in other languages, is in other languages, you may see that an enumeration is typically either explicitly or implicitly defined an underlying value, or an underlying type, that's going to be associated with its value. So in other languages you might see something in here that would be like a colon with an int that would then represent the fact that all of these values in here are going to be associated with an integer value. Where in Swift, that doesn't necessarily have to be the case, nor do we always want it to be the case. So we can do within enumerations in Swift is we can define what are known as associated values, where we can start to define these to have values or particular types in a certain way. But it's not necessarily required. We could just continue to use them this way, as we were in this previous example. So let's check out another example of that. So one way that we could do this is let's say we were creating an enumeration that was going to represent some form of an employee identifier. So let's say we had identifier and then there were multiple types. Now, one particular identifier it could be a number, so maybe you are assigned a number within your company, and maybe one way that you could be identified within your company is by a number. And then maybe another way that you could be defined or described would be via a code name. Now these two different types of values, the number and the code name, could have their own associated values. Now the way that we define those is by, at the end of the case statement, we would have open in close parentheses, in which we would define the types of those values. So let's say, just for argument's sake, the number was going to be an integer and the code name was going to be a string. So how does that affect us in what we're trying to do here? Well the interesting part now is, if I were to create a new instance of an identifier, so we would say id is gonna be equal to an identifier. And maybe, for this particular person, the identifier is going to be a number. Now we can associate a value with that particular instance of our identifier. So maybe the number is gonna be 5555. All right? And then maybe we had another instance here that was of type name, which would be Identifier.Codename. And maybe it was Brown, or something along those lines. So now I'm able to create these enumeration values, assign them to variables and have some sort of associated value with them. So then, what would we use something like that for? Well, once again, an interesting use of this would be in a switch statement. So I could now switch on a particular value. But let's say, instead of actually giving this a new value, I could simply say ID is now equal to code name. So as you can see, I could use either one. So let's go ahead and comment this out for the moment. And at this point we have ID being set to identifier.number with five fives on it. So at this point I wanna switch on ID. And then I'm gonna do another case statement or a couple different case statements. And depending on the type of identifier that is assigned to you, I want to do some sort of logic. So let's say, in this case, I want to match on the dot number. But not only do I want to match on the dot number, but I want to bind the value that's associated with that number to a variable so that I could use it within my case statement. So I would do that by using the let keyword. So this is along the terms of the pattern matching that we've talked about before I want to bind I want to do value binding of the value that's within this number, enumerated value. And I want to assign that to N. Now, at this point I can then put in my colon. And then I'll come down in here and I'll printout Employee Number is. And then I'll just go ahead and print that out as N like so. And then I can do another case statement. And at this point, I could say that I want to match on a code name, where I want to let the string associated with that code name be c, or whatever you would like for it to be. And then I'll go ahead and simply print out, Codename is, and then I'll just print that out again. C, like that. So we can go ahead and save. And then if I were to run my application at this point, you will see that because I have created an ID which is of enumerated type number that has an associated value of 5555. I have come in and I have tripped this first case statement. Then my 5555 has been bound to my end variable here with the let keyword. And then I've printed out employee number is 5555. But if I were to have changed ID and said that equal to code name Brown, and then I run this again. This time it's going to match on the dot code name and then it's going to assign or bind that value to the C variable with the like keyword, and then print out code name is Brown. So that's pretty cool. So we're able to really use some flexibility here and we don't have to stop there, we don't have to just have a single value associated with these values here. I could put in as many as I want. I could have an int and a string and another int and a boolean, and I could do all these different types of things here and then associate the proper data with those enumerable types. Now this is a very cool feature and something that you don't really see in very many other languages, so it's something that you really have a very new opportunity to use within your applications. Now, one final example that I want to use is to talk about what I alluded to earlier, about how you can associate a particular type of value with all the values within your enumeration, and within the world of Swift, we call those raw values. So I can create another enumeration, and we'll use a similar example to what we used before and we'll use direction. At this point, we can now use that colon syntax and specify what the underlying type is we want to use for all of them. So let's say this point, just for example, we want to associate all these values with an integer type. So now, what we can do here is we can once again define these, we can say case north is going to be equal to 1. Case south is going to be equal to 2. Case east is gonna be equal to 3 and case west is gonna be equal to 4. So now we've not only creating an enumeration that contains a bunch of different values, but we have values associated with those. Now this is just a very simple example where I'm using integer values here, but we could use anything we wanted in there. We could have underlying types of strings or Booleans or whatever have you or whatever you want them ultimately to be. Now, another nice feature of the Swift enumeration, which you'll see in other languages as well, is that I can start to remove some of these values, and just have it implicitly assign those raw values. So I could start off by defining the first one as one. And then Swift will look at this and assume at this point that I want all of them to have values incrementing up from the number 1. So if I were to go down through the rest of these, south would implicitly be 2, east would be 3 and west would be 4. Now the nice thing about this is that not only are we creating these different enumerated values that have associated values, but we can get at them as well. So if I were once again create a direction, I could set it to direction.north. And I could also get at that particular value by saying I want to go into the variable and I want to get its raw value. And specifying raw value is where you're going to get out this particular value that you've put in there. So in this case, as you can see, it's an integer because that's the way we've defined it. But let's say, for some reason, we define this as a string. And then, within here, we named this 1. Now, in here I could say I want I want to get the raw value and you're gonna see here that it's a string. So now, we can have other values associated with our enumerated values, just like you might have been comfortable with working in other languages.