This workshop will be retired on May 31, 2020.
Assigning an Empty Gate9:15 with Pasan Premaratne
Let's finish off our gate manager by returning an empty gate for the correct terminal.
The next method we need to implement, 0:00 is actually returning an empty gate, given a set of gates for a terminal. 0:02 This is quite simple. 0:07 So, we'll create a new method. 0:09 We'll say func emptyGate. 0:11 This method also takes an argument of gates of type string, 0:15 array of ints, like before. 0:19 And we'll be passing either one of our stored properties as an argument to this 0:22 method, just like the previous method. 0:26 Because we need to modify the gate that we're passing in, 0:29 we'll also pass this in by reference. 0:32 So we'll say inout gates, and we'll just copy this type over. 0:35 And then once we find an empty gate, well we want to return it. 0:45 So we'll say return optional Int. 0:48 Inside the method we'll check the array using the key empty and 0:52 return the first value in the array. 0:56 Because all we need is an empty gate, we don't want a specific one. 0:59 So I'll say guard let gate 1:02 = gates empty .first 1:08 else return nil. 1:13 So the first property on an array returns the first 1:17 element in that array if it exists or nil otherwise. 1:21 Now if we do get a gate, if all of this works, we'll update the gates. 1:25 We'll say update gates using gate that we just found. 1:32 You'll notice that when we call a method that uses an inout parameter. 1:39 So here we're calling the method update that we declared earlier. 1:43 Since gates here uses an inout parameter, it automatically appends or 1:47 prepend's an ampersand to the value that is being passed in. 1:53 This indicates to the compiler that we're passing in by reference. 1:58 Okay, so now, we've gotten the first empty gate inside of a gate collection. 2:02 We've updated it to move that gate from the empty list to the occupied list, so 2:08 now we can return the gate. 2:13 The last bit of code for the gate manager involves figuring out 2:17 which stored property to use for each terminal. 2:20 So up here we have a couple of different ones. 2:23 We know for Delta we need to use terminal A, American B, and so on. 2:25 So for that will create a third method at the bottom. 2:30 We'll say func, gateFor terminal. 2:35 And return in optional Int. 2:42 So in this body, we'll switch on terminal which as we know is an enum and for each 2:46 case we'll call the empty gate method, and pass in the correct dictionary. 2:52 So for terminal A, we'll say return empty gate for gates for terminal A. 2:58 We'll repeat this process. 3:08 So we'll say for Terminal B, 3:09 we want to return emptyGate using the gatesForTerminalB property. 3:12 And you know the drill. 3:20 Now we have a fully functioning gate manager. 3:40 There is, however, one tricky issue. 3:44 To highlight this, I'm going to copy most of the code over to a playground. 3:47 But I'll set runway, terminal, and 3:52 gate manager as individual types rather than nested types. 3:54 So I'm going to copy everything, hit File > New > Playground. 3:58 And I'm just going to save this on the desktop. 4:05 Okay, so I'll replace everything. 4:11 And I'm going to take these three types, runway, terminal, and gate manager, 4:17 and set them as top level types. 4:26 Okay, now at the bottom here, let's create an instance of gate manager to use and 4:31 get an empty gate in terminal A to make sure that this works. 4:35 So we'll say let gateManager = GateManager, 4:38 gateManager.gate for terminal A. 4:47 If this works, we should get gate nine. 4:54 We see there's an array up here. 4:59 Aha. We'll just change this type from 5:02 ControlTower.Runway to just Runway. 5:05 And now, there we go. 5:11 We have gate 9. 5:12 Okay, all good so far. 5:14 Now, what if we asked the gate manager for a gate again? 5:16 Well, we should get, so if we look at our list over here, so 5:19 our empty list for terminal A has gate 9. 5:23 That's occupied now, so the next gate we get should be gate 10. 5:26 So let's try that. 5:29 So down here, I'll say gateManager. 5:30 And then gateFor, again, terminal A. 5:34 Okay, so far, so good. 5:40 Now what if by mistake we just happened to create another instance of GateManager. 5:42 So we'll say let anotherGateManager, 5:47 and we ask this second GateManager for a gate instead of the first one. 5:56 Again for terminal A. 6:00 Say anotherGateManager, gateFor terminal A. 6:02 Well we now get 9 again, which is clearly incorrect. 6:07 There is currently an airplane sitting at gate 9. 6:12 This isn't the right behavior. 6:15 What we need is for all instances of GateManager to be in sync. 6:18 There is a design pattern to achieve this known as the singleton pattern. 6:23 In a singleton pattern, you design your class in such a way 6:28 that creating an instance always returns the exact same instance. 6:32 When we initialize a singleton for the first time, we create an instance. 6:37 Every time we initialize the class there after, 6:43 we simply return that first instance for use. 6:45 This ensures that we cannot create two instances of GateManager with 6:49 different sets of stored properties to manage our gates. 6:54 Creating a singleton instance in Swift is fairly easy. 6:58 In fact it's just one line of code. 7:01 So if we go back to GateManager, and at the top I'm 7:04 going to say static let sharedInstance = and 7:10 I'll create an instance in here of GateManager. 7:17 Now typically when we're creating a singleton, 7:21 we always name it sharedInstance. 7:24 And we're going to assign an instance of GateManager to it. 7:26 Swift automatically ensures under the hood 7:29 that we get this exact instance back every time. 7:32 The complexities of how this is done is a bit advanced for us, but I've let some 7:36 notes in the links about singleton's in Swift for extra reading if you're curious. 7:41 A singleton is one of those design patterns, that are abused quite often. 7:46 And so, we really need to be careful about what we use singletons for. 7:50 The reasons for 7:54 why singletons aren't always good, are kind of beyond us right now. 7:55 We'll get to some of those advanced topics in the future. 7:59 But as always, check the teacher's notes, if you're curious to learn more. 8:02 Now, instead of creating new instances, down here 8:07 we can call the sharedInstance property every time. 8:12 And now you'll see that we always get the same instance back because 8:17 here we get gate 8, or gate 11 going in the opposite direction. 8:22 Okay, so this works, so let's go back. 8:26 So I'm going to go back to my main project and add this at the very top. 8:29 So I'll say, static let sharedInstance = GateManager. 8:35 This design isn't foolproof however. 8:44 Someone can still call the classes init method and go around the singleton. 8:47 So rather than calling shared instance, they can simply initialize the class. 8:52 To prevent that happening, there's another neat trick. 8:56 We can make the initializer private, 8:59 such that it can only be used from within this file. 9:01 So, I'll say private, init, and we'll just use an empty initializer. 9:04 Now, we're always going to have one and only one GateManager. 9:10
You need to sign up for Treehouse in order to download course files.Sign up