Previous episode: 11. Download Music
Next episode: 13. Challenge: Download Images
Get immediate access to this and 4,000+ other videos and books.
Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and
4,000+ professional videos in a single subscription, it's simply the best investment you can make in
your development career.
Errors happen all the time, especially when working with networks. There are two levels of errors to think about when working with URL requests: thrown errors from the functions themselves and non-successful HTTP status codes. You're currently technically handling both, whether it's by using try statements for functions that throw or actually checking that the response code is a value of 200. You print debug statements to the console for both. This is not, however, the best way to handle errors. First, you don't wanna have print statements in production builds of your app. It's fine for you to debug while developing but not for a release version. Second, while you do check for these errors, none of it bubbles up to the end user. If something goes wrong with downloading the song, your users get no feedback or indication. With the current implementation, what would happen? Would the progress view be hidden and the button title revert back to Download? I don't know, and you possibly don't as well. That's because we haven't explicitly handled this scenario and this is what users might run into, especially when it comes to all the different types of network connections and speeds to be encountered. Let's add some better error handling to the app. Start by opening the starter project for this episode, which is just a continuation from where the last episode left off. Open SongDownloader.swift and update the downloadSong method. You add the throws keyword to indicate that this method can throw errors that will need to be handled. You can bubble up the thrown errors from the asynchronous data function on URLSession, but you don't really have any errors to bubble up and throw if the status code is invalid. Add the following code inside SongDownloader. This adds an enum of possible errors that can occur. The first error is for when there is an invalid response from the request. Next, inside downloadSong, remove the question mark from the try line that performs the download and remove the guard that's no longer necessary. Perfect. You no longer print to the console as the only error-handling mechanism if something goes wrong with a request. You bubble up the error thrown from the download method itself. An alternative solution to this could be to keep the guard statement and instead of bubbling up the error, you throw your own custom error. Either solution is fine, so let's move on. Next up is the print statement for when the response's status code is not 200. Replace the code inside the guard statement with the following. Pretty straightforward so far. Since there's no specific thrown error when checking the status code that can be bubbled up, you throw your own custom invalidResponse error. The work that gets done next in this method revolves around FileManager and acquiring the app's documentDirectory, so add an additional case to your errors enum, and then change the code in the next guard statement. The last error that you have is a print statement for when copying the downloaded song to permanent storage fails. Add one more error case to your enum, and replace the print statement with the following. All the work you needed in song downloaded has been done. Now the UI code needs to be updated as the downloadSong method can throw errors. Open SongDetailView.swift. First, add a property that'll control whether an alert is shown to the user if the download fails. It's a @State property as it'll work with swift UI and marked with @MainActor attribute in order to ensure any state changes happen on the main thread. Now you have to handle the error inside of downloadTapped. This is happening because the downloadSong method in SongDownloader can now throw errors, but they're not being handled here. Update the code that calls downloadSong with the following. You add try when calling downloadSong and wrap everything inside a do-catch block. The print statement is just a fun way to visualize your errors thrown from downloadSong, but feel free to remove that code if you aren't interested in seeing that print statement or before shipping your app. Finally, update the view code to actually show the alert using your new property. Add this modifier to your button just before the disabled modifier. Build and run your app. Tap Download and check out the results. If the download went well, then you shouldn't see any different behavior from what the app was doing in the previous episode. If an error were to occur, however, then an alert will be shown in order to tell users that something went wrong. It might be tricky to get an error to happen. Try disconnecting your computer or device from the internet and tapping the Download button, or alternatively set your showDownloadFailedAlert to true at the end of the do block in order to manually trigger an alert. Run your code one last time. Excellent. Don't forget to change the code back so you don't end up shipping an inadvertent bug. Congrats. You've done very little changes to the actual look of your app, but behind the scenes, you're now handling errors in a much better way. As you expand your downloadSong method of SongDownloader or if you add more methods and functionality to SongDownloader itself, you've not only added an enum you can use to throw the same or new errors, but you've also established good error-handling patterns in your code. Join me in the next episode, a challenge episode, where you'll put some of your recently acquired knowledge to the test. See ya there.
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.