Learn Swift and iOS Development
Master iOS development through in-depth tutorials and comprehensive courses on Swift, SwiftUI, UIKit, Core Data, and more.
Master iOS development through in-depth tutorials and comprehensive courses on Swift, SwiftUI, UIKit, Core Data, and more.
11:04
You learned in the previous episode that it is fine to ignore some of the gaps Xcode finds in your test suite. Even though the goal isn't to fill every gap, we need to write a few more unit tests for the APIClient class.
in Networking
11:05
Unit tests are very useful for testing edge cases. We explored that in the previous episode. Because bugs sometimes hide in edge cases, unit tests can help you track down hard to find bugs. This is only true if the unit tests you write are sound and cover your code.
in Networking
8:25
One of the key benefits of a robust test suite is its ability to quickly and easily test scenarios that are uncommon or hard to reproduce. In this and the next episode, we write unit tests for several scenarios that are difficult to test manually. Manual testing has value, but it is time-consuming and it can be tedious to test edge cases.
in Networking
11:55
Step by step we are increasing the code coverage of the APIClient class. In the previous episode, you learned how to use the APIs the APIClient class exposes to unit test its private methods. Remember that the goal isn't to unit test the private methods of the APIClient class. The goal is to increase the code coverage of the APIClient class. We have a few more unit tests to write.
in Networking
8:33
Code coverage is a very helpful tool to detect gaps in a test suite. In the previous episode, we enabled code coverage to learn how to write better unit tests for the APIClient class. The coverage report shows that the episodes() method is fully covered. It also reveals that the private request(:) method lacks coverage. Even though the request(:) method is private to the APIClient class, we can write unit tests to indirectly test it and increase coverage of the APIClient class. That is the focus of this episode.
in Networking
7:10
Are the unit tests we wrote for the /api/v1/episodes endpoint sufficient? How many unit tests should we write? These are some of the questions we answer in this episode. Developers often struggle with unit testing because they aren't sure when enough is enough. As a developer, you want a simple, straightforward answer. The good news is that code coverage can provide that answer.
in Networking
9:29
We can drastically improve the unit tests we wrote in the previous episodes. Even though the unit tests pass without issues, string literals and code duplication are subtle hints that we should take another look at the unit tests we wrote. At the end of this episode, we have a framework in place that we can use for the remaining unit tests of the APIClient class.
in Networking
8:42
To create a robust test suite, we need to be in control of the environment the test suite runs in. That includes being in control of the requests the application sends to the Cocoacasts API. We don't want the application to hit the Cocoacasts API when the test suite is run. In this episode, I show you how to stub the Cocoacasts API using the OHHTTPStubs library.
in Networking
7:45
Even though the unit test we wrote in the previous episode passes, we quickly discovered that it gives us a false sense of confidence. The unit test passes because it is executed synchronously. To unit test the networking layer, we need to replace the synchronous unit test with an asynchronous unit test. Let me show you how that works.
in Networking
10:32
The networking layer we are building is nearing completion. We added support for most endpoints of the Cocoacasts API and, later in this series, we add support for refreshing an access token using a refresh token. In the next few episodes, we focus on unit testing the networking layer.
in Networking
7:57
In the previous episodes, we added support for fetching, creating, and updating video progress. In this episode, you learn how to delete the progress for a video, the D in CRUD. Deleting the progress for a video is a bit special because the body of the response is empty. Let me show you what changes we need to make to add support for deleting the progress for a video.
in Networking
6:40
In the previous episode, you learned about CRUD operations and we applied this to video progress. We added the ability to fetch the progress for a video, the R in CRUD. In this episode, we cover creating and updating video progress, the C and U in CRUD.
in Networking
9:49
At this point, you should have a good understanding of the networking layer we are building. Even though we have written quite a bit of code, the networking layer we built isn't complex. We simply combined a number of common patterns and techniques to create a solution that is easy to use and extend. Later in this series, I show you that it is also easy to test.
in Networking
7:52
The video view model is no longer required to pass an access token to the API client if it requests the video of an episode. That is a welcome improvement. The API client passes an access token to an APIEndpoint object and it is the APIEndpoint object that decides when it is appropriate to add an Authorization header to a request. The changes we made in the previous episode improved the networking layer we are building.
in Networking
9:55
In the previous episode, we extended the API client with the ability to fetch the video for an episode. Because videos are protected resources, the request includes an Authorization header with an access token as its value. The solution we implemented works, but it is tedious to pass the access token to the API client and the object invoking the video(id:accessToken:) method shouldn't need to deal with access tokens. That is a responsibility of the API client.
in Networking
10:07
In this and the next episodes, we add the ability for the user to watch an episode. For that to work, the application needs to fetch the video for the episode from the mock API. Fetching a video is similar to fetching the list of episodes. The difference is that the user needs to be signed in to fetch a video because a video is a protected resource. The request to the /videos/:id endpoint needs to include an Authorization header. The value of the Authorization header is the access token the application receives after successfully signing in.
in Networking
8:16
Earlier in this series, we declared the computed message property in the APIError enum. While that seemed like a good idea at that time, the previous episode showed that we need a solution that is more flexible. The APIError enum doesn't have the context it needs to define a human-readable message for each of its cases.
in Networking
10:07
The user needs to be signed in to watch a video so the next feature we implement is the ability for the user to sign in with their email and password. This episode illustrates how a proper foundation can save time and reduce complexity. The improvements we made in the previous episode simplify the changes we need to make in this and the next episodes.
in Networking
8:04
Because the application will interface with a number of endpoints of the mock API, we need to make sure the API client is easy to extend. The more we can reduce code duplication, the easier it is to extend and maintain the API client. In this episode, I show you how to use generics to make the API client extensible and easy to maintain.
in Networking
9:27
Even though there is nothing inherently wrong with a view model performing network requests, it isn't an approach I recommend. Moving the networking logic out of the view model has a number of benefits. It reduces code duplication, facilitates unit testing, and improves the maintainability of the project to name a few.
in Networking
9:24
Handling errors is one of the less enjoyable aspects of software development, but it is an important one. You don't want to show the user a cryptic error message when something goes wrong, or worse, no error message. There is no clear-cut recipe you can follow. Every project is different. The good news is that error handling is built into Swift and the Combine framework. Let me show you how we can improve the code we wrote in the previous episode.
in Networking
8:01
We start this series by making a simple GET request to the mock API to fetch the list of episodes. We won't be using a third party library. One of the goals of this series is to show you how to build a modern networking layer that relies on Foundation's URLSession API. It is simpler than you might think.
in Networking
6:30
Most applications talk to a remote API in some way, shape, or form. Networking is therefore an important aspect of software development. Sending a request to a remote API isn't difficult, but there is more to it. In this series, you build a modern networking layer for a Swift application using Foundation's URLSession API. We cover a range of topics, basic and more advanced, from making a simple GET request to signing requests with an access token. We make use of generics and protocol-oriented programming to create a networking layer that is flexible, testable, and easy to extend.
in Networking
10:48
In the previous episodes, we implemented a service to fetch and cache remote images. Even though the service we built is pretty flexible, some applications require a more powerful solution and more options to fit their needs. This episode focuses on Kingfisher, a popular, open source library to fetch and cache remote images. You learn how to integrate Kingfisher in a project using CocoaPods. I show you how Kingfisher differs from the service we created earlier in this series and we take a peek under the hood to learn how Kingfisher does its magic.
in Networking
12:41
Earlier in this series, you learned that a cache on disk has a number of benefits. It persists the cache across launches and it can be used to seed a cache in memory. Even though modern devices have plenty of disk space, we need to be mindful of the space the cache on disk takes up on the user's device. Applications like Twitter and Instagram fetch hundreds if not thousands of images. Even if those images are optimized and small in size, the cache on disk can grow quickly, taking up a non-trivial amount of space on the user's device. In this episode, we add the ability to limit the size of the cache on disk, similar to how the image service limits the size of the cache in memory.
in Networking
10:41
The previous episodes have illustrated that caching images can result in significant performance improvements. In the previous episode, I stressed the importance of writing cached images to disk on a background thread to prevent the image service from blocking the main thread.
in Networking
9:27
In this episode, we continue to improve the solution we implemented in this series by caching images on disk. Caching images on disk has a number of benefits. It reduces the number of requests the application makes and it improves the performance of the application. The user experiences the application as fast and snappy.
in Networking
9:44
We added the ability to cancel image requests in the previous episode. This and the next episode focus on caching images. We start simple by caching images in memory.
in Networking
10:19
Most applications display images in some way, shape, or form. Those images are often fetched from a remote server, introducing a number of interesting challenges. Performing a request to a remote server takes time and it requires resources. It is therefore important to consider solutions to minimize the number of requests an application makes.
in Networking
AFNetworking has always been one of my favorite libraries and Alamofire is just as easy to like. Since the introduction of URLSession in iOS 7 and macOS Mavericks, I've been more reluctant to include either libraries in my projects. Why is that?
in Networking
In addition to being a class, URLSession is a technology that provides the infrastructure for networking, exposed through a modern and elegant API. In this series, I introduce you to the URLSession stack. You learn how easy it is to get started with URLSession and you discover that URLSession exposes a flexible API that should meet anyone's networking needs.
in Networking
In this tutorial, we take a look at three APIs to make a PUT or a POST request in Swift, (1) a completion handler, (2) Swift concurrency, and (3) a reactive approach using the Combine framework.
in Networking
Security is a vital aspect of every piece of software. Apple has made this very clear with the introduction of App Transport Security (ATS for short) several years ago. The company introduced App Transport Security alongside iOS 9 and macOS 10.11 (El Capitan) during WWDC 2015.
in Networking
In this episode, you learn how to authenticate a user using basic authentication, or basic auth for short, in Swift. We use the URLSession API in this episode, but the concepts we discuss apply to any networking library or framework that can send requests over HTTP(S).
in Networking
There are plenty of third-party libraries you can use to perform HTTP requests in Swift, but I always default to Foundation's URLSession API. It is a first-party API and easy to use. The fewer dependencies a project has, the better. Right? In this tutorial, you learn how easy it is to perform an HTTP request in Swift using the URLSession API. I show you how to fetch a remote image and JSON data.
in Networking
Most applications need to fetch data from a remote server and downloading images is a very common task applications need to perform. In this series, I show you how to download images using Swift. We take a look at several solutions. I show you the pros and cons of each solution and, most importantly, which pitfalls to avoid.
in Networking