Enum Associated Values + Swift Result Type

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi my name is stuart lynch i've created a number of videos going over the various applications of enums in swift in this video i'd like to focus on associated values as well as storing a simple value enums can store associated values attached to each case this lets you attach additional information to your enums so they can represent more specific information in this video we'll see how we can work with associated values and as a bonus i investigate a very special one the swift result type and show how it all ties in with throwing functions and completion handlers before i get started i just want to ask that if you like what i'm doing and this video in particular please leave a comment and give the video a thumbs up you can also subscribe to the channel to get notifications of new releases and it really encourages me and helps me to grow the channel so let's go to keep me focused i've created a simple playground and you can download it from the link in the description below there are two pages and neither of them have much in them but i have sectioned off my examples using a code closure function what this function allows me to do is to keep all of my code separated and allows me to because of the code in a closure use the same enum or variables over again without having to worry about name conflicts and it keeps my printouts to the console nice and organized this public function is found in the sources folder and if you've watched some of my other videos that use playgrounds you may have seen this before it's a technique that i borrowed from the ray wunderlich videos so let's get started in our first example i've already created a car enum for you so let's create an instance of this using the case suv now if i print car i see that suv prints out on the console but it isn't really a string so if i wanted to print out this all uppercase i would get this error telling me that the car has no member upper case well we can fix this by specifying that the enum car is of type string and this is an associated type not an associated value but an associated type and then we can use the raw value of the enum which will convert the case to a string and then because it is a string strings have an uppercase function now i've covered enums in a previous video and i'll leave a link in the notes below i even introduced associated values in that video but i want to try and show the difference between raw values and associated values and associated types in this video more clearly and dig a little deeper first though if you don't want to use the automatic conversion of the case to a string you can override this by assigning a specific string to one or more of the cases like this i can create a new instance and i'll call it car 2 and it will be the case convertible let me print car 2 and car 2 dot raw value respectively we see that car 2 prints out convertible but the cartoon raw value prints out car with no top so as long as we assign a string to each of the cases we can override the default raw value representation now i'm going to copy that inum from example one into example two but i'll remove the string associated type and notice i said type again not value and i'm going to change it to a double and of course this gives me an error because car with no top isn't a double so i'll remove that and the error goes away now we already have an instance of car created so we can print car but let's also print out its raw value this time we still get suv for the first print but 1.0 for the second one because if no override value is provided the cases start at zero and increment by one so the suv's raw value is 1.0 because it's a double so let's assume that we want to use overrides to represent the corresponding price so let me add some these are the average prices for these type of vehicles okay well this is fine and good but not every convertible costs 53 900 or each suv 38015 etc each make and model vary so the enum is basically useless and this is where associated values will come in handy let's copy that same enum from example one into example three but this time we're going to be removing the associated type of the enum entirely instead we're going to use an associated value for each of the cases we can do this by specifying the type for each case like a function parameter in its definition it just so happens that all of our associated types are doubles here but as you'll see shortly that's not necessarily required now when i want to create an instance of car and specify the case we need to pass in a double value for its argument so for example car.convertible at a price of fifty six thousand dollars each instance can assign a different price if we print car we see that we get convertible with a price of 56 000 we wouldn't however be able to use this price in any string interpolation or anything if i wanted to extract just the price what would i do well we can do this by creating a computed property for our enum and i'll call it price which is a double and i'm going to switch on all the cases what we do is we switch on self and since we need to cover all of the different cases i'm going to let xcode do the code completion for us and we see we get the syntax required it uses the argument name and then creates a constant that we can use in our switch in our case all we want to do is return that price for each case now i can use print car.price now what if i actually wanted to get the car type of our enum as well well we could do this again by creating another computed property and i'm going to call it description which will be a string i'm going to start exactly the same way as we did in the price example and i'm going to switch on self and let xcode generate the cases i don't need to use price at all and there is no requirement in our switch statement to include the argument so we can simply remove them and i'll just return a text representation of our vehicle type and now we can print out our instances description so as you can see an enum with an associated value with a computed property can be very powerful let's take a look at another example where the associated values for each case are different types within example four's block let's first create an enum called size and it has no associated type or values for any of its cases the cases are small medium and large and we can write all these cases on a single line next i'm going to create an enum called menu item that has three cases and coke has an associated value of size which is of type size burger has an associated value of quantity which is of type int and fry's has an associated value of size which is of type size as well so let's create an order that is an array of menu item for say instances of a small coke a burger with a quantity of two and fries whose size is large just the way i like them well now i can create a print function that will print out our order so again i'm going to let xcode generate the code for all cases and for each case i'm going to print out the menu item using string interpolation so now if i want to print out our order i can simply call that function passing in our order so that's enums with associated values you might want to stick around for the next bit though as you may find that it will clear up some things for you i'm going to talk about throwing functions completion handlers and the switch result type and hopefully by the end you'll understand the relationship they all have with an enum and associated values i'm going to take this slowly and break it up into two parts i do want to look at the swift result type but before i do that i want to take a look at how we did things before the result type became available to us in swift 5. let's take a look at a bit of a fabricated example i'm going to create a function that may create an error and it will be a throwing function and throwing functions are those that will flag up errors if problems happen and swift requires you to handle those errors in your code and to make a throwing function you just write throws before the function's return value so the function i'm going to create is one i'm going to call quotient that has two parameters a dividend and a divisor both will be doubles an error will be thrown if our dividend is divided by a divisor that is zero you can't divide by zero so if you're not familiar with throwing functions you can watch this video that i created and i'll leave a link in the description below but before i create this function then let's create an error e new that i'll call div error that conforms to the error protocol and it has one case only div by zero error now with that error created we can create our function and i said i'm going to call it quotient with dividend and divisor as our parameters and it will return a double but because it may create an error if our divisor is zero we can designate it as a throwing function here by adding that keyword before our return it'll throw an error if divisor is equal to zero and the error that we want to throw is our div error with the case of divide by zero otherwise we can just return dividend divided by divisor but we could use this function now and it's arguably better because this will catch the deadly division by zero error let's say now that we have some asynchronous tasks that when we want to call this it does a bunch of stuff and then at the end it calls this quotient function it takes so long to perform that it would freeze up our ui so we don't want to hold up that ui we need to create a function that returns our result as part of a completion handler with a completion handler my calling function to this fictitious function would look something like this so if i call the function do long division we'll pass in our two numbers and then the completion block is going to provide us with an answer that we'll be able to print out so that's how we're going to call the function so let me comment this out now and we'll come back to it after we've created the function but i'm going to leave it here for reference so if quotient was a regular function that didn't throw we could write our function like this it has two parameters both doubles and another one that's an escaping closure that provides a double as its argument there's no return value for the closure so it's just void and the concept of completion handlers and escaping completions are covered in another video that i'll leave a link to in the notes below now this function will do some other stuff that takes a long time as i mentioned but once it has we can then let our answer be our new quotient passing on our two numbers and once that's done we can call our completion providing the answer as the function argument now our commented out caller would work fine here except for one thing quotient is a throwing function and so we need to do a do try catch block we will try to perform the quotient function and assign it to the return answer before passing it on to our completion if it fails however we need to catch the error so with our function definition as is we're not specifying what the error type might be so we'll just print it out if we recreate this commented out function now let's pass in two numbers say 15 and five and we'll see that our completion handler is providing us with a double so we'll just call it answer and print it out great 3 is the answer now if we change num2 to 0 then the catch block will get executed and our error is printed well that's how we used to do things the problem that i have here is that the catch is happening way back in our do long division function and not here where i'd like to respond to any errors and present the user with some kind of notification now i could return a double and an error and deal with it that way but now there's a better way to do this and that's using the result type with swift 5 we get the result type and if we look up the definition we see that it's really an enum with two cases a success and a failure each with an associated type and those associated types are generic in the case of success they've used success as the generic type and in the case of a failure it's also a generic type as long as it conforms to the error protocol and they've just called that generic type failure so when i was first introduced to the result type in swift 5 i was somewhat confused and i've got an entire video on this when i realized it was simply an enum with two cases that have associated values it made much more sense so let me show you let's just copy the entire code from example 5 except for the call to do long division and see if we can use result instead so in our do long division function instead of having a double as an argument for our completion we can use a result type and it requires us to specify the two types that we expect well the success type is our answer and that's a double and the failure type is a div error now our completion needs to change it no longer has a double as the argument but rather a result which is an enum and our enum has two cases with associated values so if we're successful then our result will be the success case using the answer as the associated value now if there's an error we don't have to stop here we can call our completion handler here using the failure case and the divide by zero error is the associated value this means then that we can handle our successes and our failures at the call site so replicating the call to do long division we can pass in our two numbers and we'll see that our completions argument is going to be a result enum with a double and div error as our associated types and since result is an enum we can use a switch statement to cover both cases now this time letting xcode fix the error isn't perfect as it can't infer the associated type since they're generic but we know that the case success is our answer which is a double and the failure case is an error and we know that it is of type div error so we can print out the answer or print out the error just as before running this with input values of 15 and 3 we get the result of 5 and this time if it fails we can print out the error and it gets printed out now but this time it's being called or printed at the call site so i could present the user with a notification or an alert now i can do one last thing to fix this up i'm going to go back to my enum for div error and create a localized description for our error and this is a computed property of type string that returns an ns localized string it has a couple of overloads but the one we want is the one with a key and a comment both are strings and the key string is what is going to be used as the localized description so we can type something here that's appropriate and we can just leave the comment as an empty string now the comment string is ignored by the application if you're going to be localizing your application to multiple languages the comment string is used for the translator's benefit to add meaning to the contextual usage of the key where it's found in your application now instead of printing out error we can print out error dot localized description you may have seen that before and that's it i hope this gives you a better understanding of associated values and how you might want to use them in your code and at the same time cleared up any issues you might have had with the result type [Music] i have lots of other videos available and in the queue as well so please check out the rest of my channel you can also visit my website to see the apps that i have available on the app store and visit my github page to see what i have available as public repositories if you like what you've seen give it a thumbs up and subscribe to my channel and ring the bell to get notified when i post new videos i'm most active on twitter so please follow me there as well to find out what else i'm up to thanks for watching
Info
Channel: Stewart Lynch
Views: 1,569
Rating: undefined out of 5
Keywords: Enum, Associated Value, Result, Xcode, Swift
Id: wLg4wZQsWd0
Channel Id: undefined
Length: 21min 9sec (1269 seconds)
Published: Sun Jan 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.