Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
by
FREELessons:30Length:4.8 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

4.3 Exceptions

Swift 2 has completely revamped the way that we developers will use, interact with, and handle errors. Personally, I love the change and feel that it allows more control and structure of error-handling code. Let's take a look at creating, catching and handling exceptions.

4.3 Exceptions

The next important topic to cover when we're talking about controlling the flow of our application, interestingly enough has to do with the bad side or the CD underbelly of Swift. And I'm not saying that because this is necessarily a bad thing, this is just because it's a necessary evil that we have to deal with that we need to keep in the forefront of our minds. And that happens to be dealing with errors and error handling and exceptions. So what exactly does all this mean? Well, at certain points in your application you're gonna run into problems, where, things are gonna go wrong and errors are gonna happen. Now, what's new and interesting about Swift 2.0, is Apple has kind of redefined, how we as developers are going to realize errors handle errors and do other things with those errors. Now before you would typically have to pass in a reference to an error variable to a lot of different functions and methods throughout the different libraries associated with iOS and OSX development. And then you'd have to check to see if that value came back as anything because if it did come back as something then you were going to have to do something to handle that error and it was just kind of a mess. And it's really not a very fun or easy way to deal with errors. And so what Apple has done is they've kind of restructured it a little bit for us. So we're gonna start with the basics here, as what exactly is an error when it comes to Swift and how do we work with it? So an error is actually, or an exception is actually a very interesting type that's going to be decorated by a protocol. Now a protocol is really just kind of an interface, I guess if you'd ever heard of that type of terminology in other programming languages. But it's really just a contract that some type or something agrees to abide by. And actually the interesting thing about protocols and air handling within Swift is that the protocol that we're going to use is called error type. And error type is actually empty, there's really nothing there. It's just used to decorate certain things and on this case, an enumeration to specify that this particular enumeration is an error and can be thrown and caught and determined what's happening within our application by decorating with this type. So, let's start to create an example here. So, I'm going to create an enumeration. Now, an enumeration is something we haven't talk about yet, but we're gonna talk about it in an upcoming section. An enumeration is just a way to define or group together a bunch of different types or different values that we can refer to by name later on. So it’s just kind of a convention. So let’s say that I wanted to create a certain type of error. And we’re just gonna call this MySpecialError. And the way that we use that error type is we're going to say that MySpecialError is going to conform to using the colon error type. And then we can use open and close parenthesis here to define specific values associated with MySpecialError and we do that with a case statement. So we're gonna say case we can define is many of these that we would like to. And there's a number of different ways to do this. And once again we'll talk about these in an upcoming lesson. But let's just say we had SillyError, ScaryError, and maybe IReallyLikeThisError. So the names really don't make any difference. I'm just creating my own special error type here that I can use throughout my application. Now, the way that these errors arise is that at some point during your application, you can either write the statements or the statements already written within the different libraries that you're using to actually throw this exception or throw this error. And, the way that we do that is by specifying the throw keyword and then we can throw an error. So, we can throw MySpecialError.IReallyLikeThisError. So we can do something like that. So I can go ahead and save this and if I were to run this, what you're gonna see down here is that it builds successfully but then I get a fatal error down here. And I can see the problems that are happening here and I get a bit of a dump here and then we can see that there is a fatal error. An error was raised at the top level of MySpeciaError.IReallyLikeThisError and where it occurred. So this is kind of an interesting thing that you're gonna see probably quite often, especially if you are just getting started in the world of iOS or OSX development with Swift is you're going to run into stuff like this. But it's not necessarily a bad thing. These things are put in there for a reason, and we just need to be able to handle them properly. So that is how we're gonna see these exceptions being thrown and these errors being thrown throughout different parts of our application. Now that's fine, but what we have to be able to do is, we have to be able to handle these errors and the way that we do that is actually fairly simple. Now you're not just gonna see these throw statements and throw errors just laying around willy nilly, to execute like we have here. They're typically gonna happen with in some sort of enclosure so, something like a function or a method. So, what I'm gonna do here is I'm actually going to wrap this up and I'm going to wrap this up in a function. Now, don't be intimidated, we're going to talk about functions once again up in an upcoming lesson. But, just so you can see, I'm gonna create a function using the func key word and then I'm going to give it a name, a name that I can refer to this particular function as. And we'll call this myFunction. And then we're going to have an open and closed parenthesis. And within the open and closed parenthesis is where you're gonna define the arguments that you're gonna pass into your function. And in our case I'm not too concerned about it, we'll cover that later. And then in order for us to specify what it's going to return, if anything, is by after we specify the input arguments, we're gonna do a little arrow here and we're gonna specify the return value. So let's just say It was going to return a value like a string, we could do that. But if it's not going to return a value, then we actually don't need to include that on there as well. So now what we do is we have an open and closed parenthesis and we can then define the body of our function. Now, the way that you determine whether or not a function is capable of throwing an exception. Meaning if it has a throw statement in there, is after the function signature, after the arguments that are passed in, but before the return value, you're gonna have the throws keyword here. Which means, that this particular function can have the possibility of ultimately throwing an error that we may have to handle at some point. So then don't be surprised if you would see something like this. If you were to dig into the source of my function. That at some point in there after some sort of logic, if something goes wrong then we can ultimately throw this error. So I can go ahead and save that, and use my function which obviously wouldn't normally just contain a throw statement. But it's just kind of a contrived example. So let's get out of the kind of contrived example here. And let's create a semi realistic example. So let's say we had a numeration here and this is going to be my calc error and this is going to be of error type. And the thing here I can create a whole bunch of cases here, but I'm just going to call this Case to be a div by zero. So you may be able to see where I'm going with this, but just kind of hold on and you'll see as we start to play this example out. So now let's say that I had a function here that I wanted to call divide, and this is going to take in a couple of different parameters. Now once again remember we're gonna talk about arguments and parameters to functions and all that kinda stuff later on, so don't worry too much about it. But really the way that this is going to work is we're going to specify the name that we're going to use to refer to this parameter externally and we'll call this first Value. Then we specify the name that we want to internally refer to this which we'll call first. Then we're going to give a type and we'll just say that this is gonna be a type integer. And then we do the same thing again. We're gonna have a second value which is gonna be what we're gonna refer to this value externally as. Then we're going to say second. This is also going to be an integer. And then, ultimately, we are going to return here a double. And then we'll go ahead and we'll have our actual implementation here. Now remember something could happen here, so I do want to add in this throws. At some point this particular function might actually throw an exception. So I think you know where I'm gonna go here. So let's go and start to work on this. So at this point I can now say. but I would need to do some checking here. So what we are going to assume here is we're going to divide first by second then we are going to return the result. But as you already know, I cannot divide another number by zero. So what I'm going to do here is I'm going to say if second is equal to zero. Then I want to throw a MyCalcError.DivByZero. But if it makes it out of here, then I want to simply return the double version of first divided by the double version of second. And we'll go ahead and save that. So now I can come down below here and I can simply say that I want to run my divide function and I'm going to pass in, we'll say five and two. And then we will get a result. We'll say var result is equal to divide and we'll get the result here, and then we'll simply say, print the result is, and then we'll just kind of pop it in here as result. And now we'll want to run this, but ultimately you're going to see we're going to have a problem here. And this is a nice part of the Fact that Apple has kind of redone the way that we're going to handle errors within swift, and then if I were to take a look at this exception here it says a call can throw but is not marked with try. So try is the key word that's going to show us, that ultimately we are ready and willing to say we can handle what's gonna happen with our exception here. So I'm gonna put a try in here, just to make it happy, but ultimately this isn't really gonna fix it for us. But we'll go ahead and save, and we'll run this application. And we're gonna see here that the result is 2.5, which seems to work okay, but let's say now the second value that comes in is gonna be zero. I can go ahead and run this. And now we're going to get that error again or a very similar error again that we saw before that we're getting that divide by zero which is what we would expect. So now we have called a function that is capable of throwing, we've seen it throw, and we've marked this call to this particular function with a try which is required by the compiler to do. But it's really not doing anything for us so if you've ever done any sort of other error exception handling in other languages then you might think that try is kind of that thing that's gonna mark a block of code of something that you want to attempt to do and then we wanna maybe try to catch it later but. Within Swift they've done it a little bit differently. Whereas try is really just kinda saying that, I agree to handle or do something to whatever's going to happen within the exception that could ultimately be thrown. Now the way that we handle this in a very logical way is not through a try-catch statement, but rather through a do-catch statement. So if you do recall earlier, we started to talk about the while loop, and we talked about the removal of the do-while loop. Whereas the do keyword used to specify what was going to happen the first time and all subsequent times that the while condition passes. But it was replaced with the repeat while statement while the do statement was pulled over into the error handling world. So now what we do is we're going to specify a do opened and closed curly brackets. And then down at the bottom here, we're gonna specify a catch statement with open and close curly brackets, just like this. Now it's a fairly unassuming structure here. And you're gonna see we're gonna get a little bit of a warning here that it is unreachable because there errors thrown here but we'll fix that in just a second. So what we can do now is within our do block we can take this piece of code that could ultimately throw an exception that's marked by our try. And we can cut this off and we can put it within our do statement. And that should make that a little bit happier now. And we'll also take our print statement here and we'll pull this up in as well. So we'll go ahead and paste that. So now what this is saying is, we want to try and execute this code here within our do block. Now if for some reason something bad happens and an exception is thrown, Then it's going to be made available for us to catch it in certain ways. And the interesting thing about the catch statement is I can use some of the similar pattern matching that we've learned about before to ultimately catch some of these exceptions. Or I can be very explicit with what I wanna catch. So let's say in this case, I wanted to catch the MyCalcError.DivByZeroError, which I can absolutely do. And then I could come down here and print a statement here. So I could copy this, I'll come down in here, and I'll print this out. And I'll say, you can't divide by zero, just like that. So, now I can save this. So, now I've basically done the same thing. I'm doing the same operation that I was doing before but I'm adding a little bit of protection to myself whereas now I'm marking the call to the function that could possibly throw an exception with the try keyword and then I'm wrapping the code that's going to contain that try in a do block with a catch subsequent after it. So what I could do is I could save this and I could run my block of code again and now what's gonna happen is we're going to go through and instead of throwing this big nasty exception with all sorts of nitty gritty detail. I simply got a you can't divide by zero so I don't get that error anymore. I'm simply handling it with the do catch block. Now let's say, for instance, we had something else happen which Which we had a case where it was a divide by zero, but let's also we wanted to have a case where we're dividing by one. Now, this is a little bit of a contrived example, but you'll see where I'm going with this. So we check to see if second is equal to zero. But what if else if second is equal to one? Then we'll go ahead and throw a MyCalcError.DivideByOne. Now this doesn't make much sense, I agree with you but just to show you how we could ultimately handle this. So if I were to save this now and change this to be one, I could go ahead and run this and we're gonna get that big nasty error like we did before which we don't want. So now what I can do at this point is I can be very explicit and I could catch the MyCalcError.DivideByOne. But in this case, what if I don't necessarily know all the errors or I don't have a lot of specific logic that I wanna do for all instances of all errors? So I only call out the one's specifically that I want to handle in a certain way. Like maybe the divide by zero and I'll print out a special error there. But I could also just leave this as a naked catch and then I can have this catch be the catch-all if you will, no pun intended. To ultimately handle anything else I didn't specifically match to this particular exception. And I could just do a copy here we'll copy this, we'll print it out here and we'll just say something bad happened and we'll say that. So now if I were to re-run this, I should not get a really nasty exception. We'll just say that something bad happened because I caught that using a very general catch statement here, to add a little bit of an extra layer of protection. Because, ultimately, there's no way that I'm necessarily gonna know all or really want to handle all the different types of errors that certain operations could ultimately throw at me. But, this is going to provide a very nice little catch-all.

Back to the top