Quick Tip

What’s the difference between catch and replaceError in Combine?

Published on: May 29, 2020

There are several ways to handle errors in Combine. Most commonly you will either use catch or replaceError if you want to implement a mechanism that allows you to recover from an error. For example, catch is useful if you want to retry a network operation with a delay. The catch and replaceError operators look very similar at first glance. They are both executed when an error occurs in your pipeline, and they allow you to recover from an error. However, their purposes are very different. When to use catch The catch operator is used if you want to inspect...

Read more...

Reclaim disk space by deleting old iOS simulators and Device Support files

Published on: May 24, 2020

After using a MacBook that runs Xcode for a few years it's likely that your disk space is starting to fill up good. A large part of this disk space can be occupied by Device Support files that are used by Xcode for older iOS versions, or by iOS simulators that are no longer available on your machine. To clean these files up you can do the following: Go to your Terminal and type open ~/Library/Developer/Xcode/iOS\ DeviceSupport Delete folders for iOS versions that you no longer need to support. Do the same with open ~/Library/Developer/Xcode/watchOS\ DeviceSupport Clean up unavailable simulators...

Read more...

Throttle network speeds for a specific host in Charles

Published on: May 21, 2020

Sometimes you'll want to test whether your app works properly under poor networking conditions. One way to test this is Apple's Network Link Conditioner. Unfortunately, this will slow internet speeds for your entire machine to a crawl which can be counterproductive. Especially if you want to throttle your app for a longer period of time. If you have Charles installed to debug your app's network traffic, you can use it to throttle network speeds for the entire system, or for a selection of hosts which is exactly what we're looking for. To enable throttling in Charles you can either go...

Read more...

How to have more than one type of cell in a Collection View

Published on: May 19, 2020

Collection views in iOS are awesome. You can use them to build complex custom layouts and since iOS 13 you can use Compositional Layouts to quickly build good looking layouts that would take forever to accomplish on iOS 12 and below. But what if you want to use more than one type of cell in your layout? If you're building your app without storyboard you register collection view cells using the register method on UICollectionView. If you want to use more than one cell type, all you need to do is call register multiple times: collectionView.register(CellTypeOne.self, forCellWithReuseIdentifier: "CellTypeOne") collectionView.register(CellTypeTwo.self, forCellWithReuseIdentifier:...

Read more...

Changing a publisher’s Failure type in Combine

Published on: April 15, 2020

One of Combine's somewhat painful to work with features is its error mechanism. In Combine, publishers have an Output type and a Failure type. The Output represents the values that a publisher can emit, the Failure represents the errors that a publisher can emit. This is really convenient because you know exactly what to expect from a publisher you subscribe to. But what happens when you have a slightly more complicated setup? What happens if you want to transform a publisher's output into a new publisher but the errors of the old and new publishers don't line up? The other...

Read more...

Using Closures to initialize properties in Swift

Published on: April 8, 2020

There are several ways to initialize and configure properties in Swift. In this week's Quick Tip, I would like to briefly highlight the possibility of using closures to initialize complex properties in your structs and classes. You will learn how you can use this approach of initializing properties, and when it's useful. Let's dive in with an example right away: struct PicturesApi { private let dataPublisher: URLSession.DataTaskPublisher = { let url = URL(string: "https://mywebsite.com/pictures")! return URLSession.shared.dataTaskPublisher(for: url) }() } In this example, I create a URLSession.DataTaskPublisher object using a closure that is executed immediately when PicturesApi is instantiated. Even though...

Read more...

Find and copy Xcode device support files

Published on: April 1, 2020

Every once in a while I run into a situation where I update my iPhone to the latest iOS before I realize I'm still using an older version of Xcode for some projects. I usually realize this when Xcode tells me that it "Could not locate device support files". I'm sure many folks run into this problem. Luckily, we can fix this by copying the device support files from the new Xcode over to the old Xcode, or by grabbing the device support files from an external source. Copying device support files if you already have the latest Xcode installed...

Read more...

Calculating the difference in hours between two dates in Swift

Published on: March 25, 2020

Sometimes you need to calculate the difference between two dates in a specific format. For instance, you might need to know the difference between dates in hours. Or maybe you want to find out how many days there are between two dates. One approach for this would be to determine the number of seconds between two dates using timeIntervalSince: let differenceInSeconds = lhs.timeIntervalSince(rhs) You could use this difference in seconds to convert to hours, minutes or any other unit you might need. But we can do better in Swift using DateComponents. Given two dates, you can get the difference in...

Read more...

Removing duplicate values from an array in Swift

Published on: March 18, 2020

Arrays in Swift can hold on to all kinds of data. A common desire developers have when they use arrays, is to remove duplicate values from their arrays. Doing this is, unfortunately, not trivial. Objects that you store in an array are not guaranteed to be comparable. This means that it's not always possible to determine whether two objects are the same. For example, the following model is not comparable: struct Point { let x: Int let y: Int } However, a keen eye might notice that two instances of Point could easily be compared and two points that are...

Read more...

What is @escaping in Swift?

Published on: March 11, 2020

If you've ever written or used a function that accepts a closure as one of its arguments, it's likely that you've encountered the @escaping keyword. When a closure is marked as escaping in Swift, it means that the closure will outlive, or leave the scope that you've passed it to. Let's look at an example of a non-escaping closure: func doSomething(using closure: () -> Void) { closure() } The closure passed to doSomething(using:) is executed immediately within the doSomething(using:) function. Because the closure is executed immediately within the scope of doSomething(using:) we know that nothing that we do inside of...

Read more...