In my previous post Classes In Swift — An Introduction, I mentioned that I should probably use an enumeration to denote what the status of my Message was (whether it was sent, received, or read). Now, I could write a full MessageStatus enumeration with its own file that could be imported into any project, and that would work. But really, this status is only supposed to talk about my custom class here, about my “Message” class. Why go through all of the hassle to make this some generic MessageStatus enumeration that could be used on messages completely unrelated to my Message class?
This is exactly where we would want to use a nested type!
What is a nested type?
Well, a nested type is exactly what it sounds like. I know, kind of anticlimactic. Nonetheless, they can be very useful for situations such as these. This enumeration only really makes since in this context, so it might as well actually be a nested type in our Message class.
So, let’s write a simple enumeration to describe what stage our Message currently is:
enum Status { case Sent case Received case Read }
If you want to learn more about enumerations, take a look at my previous post Enumerations in Swift.
Anyway, that is simple enough, now, how do we actually nest our nested type in Swift? All we do is put it into our Message class from before, that is, inside of its curly braces:
class Message { enum Status { case Sent case Received case Read } //Modified stuff we wrote last time... }
I’ll include the entire Message class at the end of this post.
Dot-Syntax and Type Inference with Nested Types
So, now inside our Message class, we can set our status variable to be of the nested type Status, and refer to it as Status.Sent. If the type can be inferred, we can even refer to it in the shorter way of just .Sent.
If you are outside of the Message class, with something that imports the Message class, how can you refer to this enumeration? You would just use dot notation to look inside, so our nested type’s full name would be Message.Status.Sent, which again if the type is known, you can just use .Sent.
Having these as nested types also help keep the enumerations short, particularly in their native context, so as to avoid something like the Objective-C enumeration UIImagePickerControllerCameraCaptureModePhoto. When imported into Swift, it can get shorter if the type can be inferred so you can use dot-syntax to set it to .Photo or .Video. With how the Objective-C classes are imported, currently the enumeration is a nested type named UIImagePickerControllerCameraCaptureMode, within the UIImagePickerController class, which seems a bit needlessly verbose. That means its full name is UIImagePickerController.UIImagePickerControllerCameraCaptureMode.Photo (for one setting).
If it was done fully in Swift, they probably would rename the nested enumeration CameraCaptureMode, within UIImagePickerController, resulting in its full name being UIImagePickerController.CameraCaptureMode.Video. Nonetheless, the way they did it still lets you set it to .Photo or .Video when the type is known, so that is helpful.
Using our Nested Type
Let’s modify our Message class to take advantage of this. Let’s say that this message class has a suggestion of what color to use on an indicator saying what stage the message is in on the UI. Right place for this? Probably not, but it would be one possible use for this capability. It would probably be better in something using our Message class in its UI, so it would actually refer to this enumeration as Message.Status from the external context. We will need to change our status variable as well, as shown below:
var status = Status.Sent //Change this from the original String form //Add This func statusColor() -> UIColor { switch status { case .Sent: return UIColor(red: 1, green: 0, blue: 0, alpha: 1) case .Received: return UIColor(red: 0, green: 0, blue: 1, alpha: 1) case .Read: return UIColor(red: 0, green: 1, blue: 1, alpha: 1) } }
So with that, we are storing our status in its own enumeration, and calling it from the class it is nested in.
One other note, there is no significant limit to the amount of nesting used in nested types. If you want a class in a class in a class… etc and have it 8 levels deep you can do it. If you have to call it from the top level though, you will have to still use dot-syntax to access each successive level of nesting.
Full Code for Modified Message Class
For reference, here is our newly modified Message class (we didn’t touch TextMessage or ImageMessage):
class Message { //New enum Status { case Sent case Received case Read } // let sender: String let recipient: String let timeStamp: Date var status = Status.Sent //Modified init(sender: String, recipient: String) { self.sender = sender self.recipient = recipient timeStamp = Date() } func basicInfo()->String { return "Time: \(timeStamp.description), Sender: \(sender), Recipient: \(recipient)" } func printInfo() { print(basicInfo()) } //New func statusColor() -> UIColor { switch status { case .Sent: return UIColor(red: 1, green: 0, blue: 0, alpha: 1) case .Received: return UIColor(red: 0, green: 0, blue: 1, alpha: 1) case .Read: return UIColor(red: 0, green: 1, blue: 1, alpha: 1) } } // }
Conclusion
Today’s Swift topic was rather simple, but it can be quite useful. It also helps encapsulate the code, leaving this Swift enumeration only inside our Message class, where it is actually needed. Being able to access different levels of nesting via dot-syntax is also very helpful, and helps keep the names short and easily readable.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!