How to filter an Array in Swift?

When you have an Array of elements, and you want to drop all elements that don't match specific criteria from the Array, you're looking for Array's filter(isIncluded:) method. Let's say you have an array of words and you only want to keep the words that are longer than three characters:

let words = ["hello", "world", "this", "is", "a", "list", "of", "strings"]
let filtered = words.filter { word in
  return word.count >= 3
} // filtered is ["hello", "world", "this", "list", "strings"]

The filter(isIncluded:) method takes a closure that is executed for every element in the source Array. If you return true from this closure, the element will be included in a new, filtered Array. If you return false, the element is ignored and won't be included in the new Array. When you apply a filter on an Array, the original Array is not modified. Instead, filter(isIncluded:) creates a new Array with only the elements you want.

You can perform any kind of calculation, comparison or computation in the closure that you use, just keep in mind that the more work you in your closure, the slower your filter might become. Ideally, you should make sure that you do as little work as possible when filtering an Array.

If you have any questions about this tip, or if you have feedback for me, don't hesitate to send me a Tweet!

Five tips to write better todos in Xcode

We all write the dreaded // TODO: and // FIXME: comments every once in a while. Sometimes we do it because we know our code can be better but we're not sure how, other times we don't have the time to write an optimal solution because of deadlines, and other times we just want to move on to more interesting problems to solve and we just slap a // TODO: on our code and call it a day.

In today's post, I would like to give you five tips to make sure your todos eventually get fixed and don't end up haunting your code unnoticed until the end of times.

1. Sign your todos with a date and your name

The first tip is possibly the most important in my opinion. If you leave a todo in your code, sign it with your name and with the current date. This makes it really clear to you and anybody on your team how long the todo has been there for, and how who left the todo there. The purpose is not to play the blame game or to point fingers but more to ask the original todo writer if the todo is still relevant, and whether there is a Jira ticket, Trello ticket or any other kind of ticket in whatever system you use to track work that must be done.

It's also possible to extract the todo author and date from git but this can sometimes be problematic, especially if code marked with the todo is moved around, or a typo is fixed because the todo will then carry an entire history. It's much more convenient to have the basic information about the todo item available at a glance.

2. Mark your todo with #warning

If your project has very few warnings and you tend to pay attention to the warnings that Xcode shows in your project, it's a good idea to make your todos show up as compiler warnings. You can do this by writing your todos as follows:

#warning("TODO: donnywals, 2020-01-08 - Improve this algorithm, I'm sure we can get this to O(1) somehow.")

When you write your todo as a #warning rather than a comment, Xcode will treat it as a compiler warning. This makes your todos stand out even more, and when combined with tip 1 your todos will be easily visible because they show up as warnings and you have all the context you might night right there in the warning.

3. Use SwiftLint to mark todos as warnings

An alternative to using #warning is to use SwiftLint. SwiftLint is a tool that helps you and your team write nicely formatted Swift code by analyzing your code and showing compiler warnings when you violate any of its rules. SwiftLint has a rule that flags any occurrences of a // TODO comment in your as compiler warnings.

If you don't like using #warning for your todos because you prefer comments, but also want to be warned about any todos in your code then SwiftLint is the way to go.

4. Remove todos if they don't get done for a while

To avoid everlasting todo items that never get fixed, make sure to go through and clean up your todos every once in a while. If you mark your todos with an author and a date, it's easy to find out which todos have been lingering for far too long and you can quickly reach out to your teammates to find out what the status of a todo is and whether it's still relevant.

A good approach here is to set aside an hour or so every couple of weeks to go through the project I'm working on to see if there are any todos that have been around for more than a month and where I don't know what their status is. I have noticed that when a todo has been around for more than a month or two, they have often become irrelevant, or I realize that implementing the todo hasn't been prioritized yet. This often leads to the todo getting prioritized, or removing it because the todo is no longer relevant.

5. Avoid todos altogether

This one is cheating a bit, but the best way to have better todos is just to avoid them completely. Whenever you find yourself writing a todo, ask yourself why. You'll often find that the answer is that you just want to move on to the next thing or because you're not sure how to do the thing you want to do, and for some reason, you decided that you don't want to figure it out right now. In many cases, you might just as well go ahead and do what needs to be done right away and avoid writing the todo altogether.

If you're reviewing a PR from one of your teammates and you spot a todo in their code, it's absolutely okay to ask them why the todo is there and try to convince them to take care of the todo now rather than at some time in the future. If the todo is reasonable, try to find out if the todo has been added to your ticketing system to make sure the work is prioritized eventually so the todo can be marked as completed.

In summary

I hope that with this list of ways to get better at writing todo items you can improve your codebase a little bit. Todos are inevitable in most codebases, but it's important that manage them well to avoid having lots of hidden todos in your code that nobody remembers or cares about anymore.

If you have any more tips on how you handle todos in your projects, make sure to let me know!

Getting started with Combine

The Combine framework. Silently introduced, yet hugely important for iOS. It didn't get any attention during the big Keynote at WWDC 2019, but as soon as folks were in the sessions they knew that Combine was going to be huge. It implements a Functional Reactive Programming (FRP) paradigm that's similar to that of Rx which is implemented by RxSwift, except it's made by Apple and has native support on all Apple platforms as long as they are running iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+ or tvOS 13+.

The fact that Apple created their own FRP framework is a big deal, and it gives off a signal to the developer community. SwiftUI makes heavy use of Combine and Apple has integrated Combine in several existing APIs as well. And since Combine is created and owned by Apple, it can be used without any third-party dependencies, and we can rest assured that Apple will continue to support Combine for the foreseeable future.

In today's post, I would like to help you get started with Combine and show you the basics of what it is, how it works, and what it can do. You will learn the following topics:

  • Understanding what Functional Reactive Programming is
  • Understanding publishers and subscribers
  • Transforming publishers

There is a lot to cover in this post, so make sure you're comfortable, grab yourself something to drink and put on your learning hat.

Understanding what Functional Reactive Programming is

In the world of FRP, your code is written in a way where data flows from one place to the other automatically through subscriptions. It uses the building blocks of Functional Programming like, for example, the ability to map one dataflow into another. FRP is particularly useful in applications that have data that changes over time.

For example, if you have a label that displays the value of a slider, you can use FRP to push the value of your slider through a stream, or publisher which will then send the new value of the slider to all subscribers of the stream, which could be the label that shows the slider value, or anything else.

In addition to driving UI updates, FRP is also incredibly useful in asynchronous programming. Consider a network request. When you make the request, you expect to get a result back eventually. Usually, you would pass a completion closure to your request which is then executed when the request is finished. In FRP, the method you call to make a request would return a publisher that will publish a result once the request is finished. The benefit here is that if you want to transform the result of the network request, or maybe chain it together with another request, your code will typically be easier to reason about than a heavily nested tree of completion closures.

I won't cover networking or UI updates in today's post. Instead, we'll go over some more basic examples of publishers and transforming values to prepare them for display. I will cover networking and UI updates in future posts.

Understanding publishers and subscribers

A Combine publisher is an object that sends values to its subscribers over time. Sometimes this is a single value, and other times a publisher can transmit multiple values or no values at all. While a publisher can publish a variable number of values, it can only emit a single completion or error event. Since it's common to represent the flow of a publisher as a so-called marble diagram, let's examine one now.

Example marble diagrams. Top exits normally, bottom with arrow

The image above contains two marble diagrams. Each diagram is shown as an arrow. Each arrow represents a publisher. The circles, or marbles, on each line, represent the values that the publisher emits. The top arrow has a line at the end. This line represents a completion event. After this line, the publisher will no longer publish any new values.

The bottom diagram ends with a cross. The cross represents an error event. Errors end the stream of values, similar to a completion event. In other words, something went wrong and the publisher will now no longer publish any new events. Every publisher in the Combine framework uses these same rules, with no exceptions. Even publishers that publish only a single value must publish a completion event after publishing their single value.

Subscribing to a simple publisher

We can model the stream of values that are published by a publisher as an array. In fact, we can even use arrays to drive simple publishers. Let's create a simple publisher that publishes a list of integers:

[1, 2, 3]
  .publisher
  .sink(receiveCompletion: { completion in
    switch completion {
    case .failure(let error):
      print("Something went wrong: \(error)")
    case .finished:
      print("Received Completion")
    }
  }, receiveValue: { value in
    print("Received value \(value)")
  })

There is a lot to unpack in the snippet above. The Combine framework adds a publisher property to Array. We can use this property to turn an array of values into a publisher that will publish all values in the array to the subscribers of the publisher.

The type of the created publisher is Publishers.Sequence<[Int], Never>. Based on this type signature, we can derive that there is a Publishers object in the Combine framework. You can look up the Publishers object in the documentation and you'll find this page. We can find the following short description for Publishers there:

A namespace for types that serve as publishers.

In other words, all the built-in publishers in the Combine framework are grouped under the Publishers enum. Each of the publishers that exist in this namespace conforms to the Publisher protocol and has a specific role. You will rarely have the need to directly create instances of the publishers contained in the Publishers enum. Instead, you'll often create them by calling methods or properties on other objects. Similar to how we created a Publishers.Sequence<[Int], Never> publisher by calling publisher on our array.

The generic types in the definition of Publishers.Sequence<[Int], Never> are [Int] and Never in the preceding example. This means that the publisher will use a sequence of type [Int] to publish values and that its failure type is Never. This tells us that the Sequence publisher will always complete successfully. This means that in the example above, the .failure case in the switch will never be hit and we can always assume success in the receiveCompletion closure of a sink where the failure type is Never. In fact, there is a special version of sink available on publishers that have a failure type of Never where you only supply a receiveValue closure.

Every publisher in Combine has an Output and a Failure type. The Output is the type of value that a publisher will push to its subscribers. In the case of our Sequence, the Output will be Int. The Failure type is Never because the publisher cannot finish with an error. Publishers that can fail will often use an object that conforms to Error as their Failure type, but you're free to specify any type you want.

Tip:
If you want to learn more about generics, check out some of the posts I have written on that topic:

You can subscribe to a publisher using the sink(receiveCompletion:receiveValue:) method. This method creates a subscriber that is subscribed to the publisher that the method was called on. It's important to note that publishers only publish values when they have subscribers. Calling sink(receiveCompletion:receiveValue:) on a publisher creates a subscriber immediately and enables the publisher to begin streaming values.

For posterity, the output of the preceding code snippet is the following:

Received value 1
Received value 2
Received value 3
Received Completion

The receiveValue closure is called whenever a new value is published by the publisher. This closure receives the latest value of the publisher as its single argument. In the completion handler, we can check whether a subscription failed with an error or if it completed normally. You can use a switch statement and pattern matching to extract the error and handle it as needed. Combine has more advanced error handling mechanisms that I won't go into in today's post. For now, it's important that you understand how publishers and subscriptions work at the surface.

Let's take a closer look at the subscription object that is created when you call sink(receiveCompletion:receiveValue:).

Keeping track of subscriptions

In the previous subsection, you learned a bit about subscribing to a publisher by calling sink(receiveCompletion:receiveValue:) on the publisher itself. In the example code, we did not store the object that's returned by sink(receiveCompletion:receiveValue:), which is perfectly fine in a Playground. However, in your applications, you need to hold on to the subscriptions you create. If you don't do this, the subscription object will be discarded as soon as the scope where you create the subscription is exited. So if you were to call sink in a function, the created subscription would cease to exist at the end of the function.

If you examine the return type of sink, you will find that it's AnyCancellable. An AnyCancellable object is a type-erased wrapper around a Cancellable subscription that you can hold on to in your view controller. You can safely hold on to your AnyCancellable objects and be assured that any subscriptions are canceled when the object that's holding on to the AnyCancellable is deallocated. You only need to call cancel yourself if you explicitly want to discard a given subscription.

Note:
If you have used RxSwift in the past, you may have worked with an object called DisposeBag, and you would have added Disposable objects to the DisposeBag. Combine does not have an equivalent of DisposeBag, but it does have an equivalent of Disposable which is the Cancellable protocol.

Consider the following example:

var subscription: AnyCancellable?

func subscribe() {
  let notification = UIApplication.keyboardDidShowNotification
  let publisher = NotificationCenter.default.publisher(for: notification)
  subscription = publisher.sink(receiveCompletion: { _ in
    print("Completion")
  }, receiveValue: { notification in
    print("Received notification: \(notification)")
  })
}

subscribe()
NotificationCenter.default.post(Notification(name: UIApplication.keyboardDidShowNotification))

In the preceding code, we use the convenient publisher(for:) method that was added to NotificationCenter to subscribe to the UIApplication.keyboardDidShowNotification notification. If you place this code in a Playground, you'll find that the print statement in the receiveValue closure is executed, but the receiveCompletion is never called. The reason for this is that NotificationCenter publisher can send an infinite number of notifications to its subscribers.

If you remove the assignment of subscription by removing subscription = before publisher.sink you will find that the receiveValue closure is never called due to the subscription being discarded as soon as the subscribe() function is done executing.

In addition to automatic cancellation of subscriptions when an AnyCancellable is deallocated, you can also explicitly cancel a subscription by calling cancel() on the AnyCancellable that contains the subscription, or directly on any object that conforms to Cancellable. To try this, you can add the following two lines after the code snippet I just showed you:

subscription?.cancel()
NotificationCenter.default.post(Notification(name: UIApplication.keyboardDidShowNotification))

If you put this in a playground, you'll find that the receiveValue closure is only called once because the subscription is canceled after the first notification is posted.

If you examine the type of object that is returned by publisher(for:), you'll find that it's a NotificationCenter.Publisher. This doesn't tell us much about the type of object and error it might publish. When you call sink(receiveCompletion:receiveValue:) on the publisher, you'll notice that the receiveCompletion closure has a single argument of type Subscribers.Completion<Never> and the receiveValue has an argument of type Notification. In other words, the Output of NotificationCenter.Publisher is Notification, and its Failure is Never. You can confirm this by looking up NotificationCenter.Publisher in the documentation and examing the Output and Failure type aliases.

Tip:
Speaking of type aliases, if you want to learn more about how and when to use them, check out my five ways to improve code with type aliases.

At this point, you know that Combine revolves around publishers and subscribers. You know that publishers only publish values when they have active subscribers and that you can quickly subscribe to publishers using the sink(receiveCompletion:receiveValue:) method. You saw two publishers in this section, a Publishers.Sequence<[Int], Never> publisher and a NotificationCenter.Publisher which publishes Notification objects and has Never as its error type. You also know that publishers will publish values until they emit either an error or a completion event. While this is really cool and useful already, let's look at another important key feature of Combine; transforming publishers.

Transforming publishers

When you subscribe to a publisher, you often don't want to use the values that it emits directly. Sometimes you'll want to format the output of a publisher so you can use it to update your UI, other times you need to extract some values from, for example, a notification for the published value to be useful.

Because Combine is a Functional Reactive Programming framework, it supports some of the foundational features that you might know from functional programming. Publishers support several transforming operators, like map or flatMap. We can use these transforming operators to transform every value that is emitted by a stream, into another value. Let's look at a marble diagram that describes how map works in Combine:

Example of a "map" marble diagram

The marble diagram above describes a publisher that emits values over time. By using the map operator on the publisher, a new publisher is created. Its type is Publisher.Map<Upstream, Output>. The Upstream generic must be another publisher, and the Output generic is the output of this new publisher. So when we use the earlier example where we subscribed to the UIApplication.keyboardDidShowNotification, we can extract the keyboard height and push that to subscribers instead of the full Notification object using the following code:

let publisher = NotificationCenter.default
  .publisher(for: notification)
  .map { (notification) -> CGFloat in
    guard let endFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
      return 0.0
    }

    return endFrame.cgRectValue.height
}

When you subscribe to the created publisher object you will receive CGFloat values rather than Notification objects. The type of publisher in the above example is Publishers.Map<NotificationCenter.Publisher, CGFloat>. In other words, its a map publisher that takes NotificationCenter.Publisher as its Upstream and CGFloat as its Output.

The general pattern in Combine is that every time you apply a transformation to a publisher, you create a new publisher that wraps the original publisher and has a new output. Sounds confusing? I know. Let me show you another example. This time we'll look at the collect operator. Let's look at the marble diagram first:

Example of a "collect" marble diagram

The pictured marble diagram shows that the collect operator takes values from a publisher, collects them into an array and sends them to its subscribers when a threshold is met. Let's look at this in a code example:

[1, 2, 3]
  .publisher
  .collect(2)
  .sink(receiveValue: { value in
    print("Received value \(value)")
  })

Note that I have omitted the receiveCompletion closure in the call to sink above. This is perfectly fine if you're not interested in completion events from a publisher, or if you know that it will never emit an error, which the Publishers.Sequence doesn't. After creating the sequence publisher, .collect(2) is called on the publisher which transforms it into a Publishers.CollectByCount publisher that wraps the original sequence publisher. This publisher uses the threshold that we supply and emits values whenever the threshold is met. The above code produces the following output in a playground:

Received value [1, 2]
Received value [3]

When a publisher completes before the threshold is met, the buffer is sent to the subscriber with the items that have been collected so far. If you don't specify a threshold at all, and call collect() on a publisher, the publisher is transformed into a Result<Success, Failure>.Publisher. This publisher uses an array of a publisher's output as the Success value of Result, and the Failure is the publisher's Failure. When the upstream publisher has completed, either with success or an error, the Result<Success, Failure>.Publisher will emit a single value that contains all values that were published, or an error.

Note that the collect() method with no threshold could cause your app to use an unbounded amount of memory if a publisher emits many events before completion. You'll usually want to specify a sensible threshold for your combine operations.

At the beginning of this section, I mentioned the flatMap operator. I'm not going to show how flatMap works in today's post. The reason is simple. Using flatMap is a fairly advanced concept where you can take a publisher that publishes other publishers, and you can use flatMap to publish the values from all of these publishers on a single new publisher. I will demonstrate flatMap in next week's post where we'll convert an existing networking layer to make use of Combine.

In summary

Today's post taught you the very basics of Combine. You learned what publishers are, and the basics of how they work. You learned that publishers push values to their subscribers until they have no more values to emit and are completed, or until they emit an error. You also learned that you can subscribe to a publisher using the sink(receiveCompletion:receiveValue:) method, and that this method creates an AnyCancellable object that contains the subscription and must be retained for as long as you need it to make sure your subscription stays alive.

After learning the basics of publishers and subscribers, I showed you the basics of how you can transform publishers of one type, into publishers of a different type, much like how map works on an array. The ability to chain together publishers, and transform them using different functions is one of the most powerful features of FRP and you will find that these transformations truly are the heart of Combine once you start using it more often.

This post is part of an ongoing series I'm planning to do where I will gradually teach you more and more about Combine using practical examples and sometimes more theoretical overviews. You can find all the posts in this series right here. This post is the first post in this series so if you're reading this post early after I published it, there probably isn't much else to read yet. Make sure to subscribe to my newsletter below, and to follow me on Twitter to be notified when I publish new content.

Swift’s typealias explained with five examples

Swift grants developers the ability to shadow certain types with an alternative name using the typealias keyword. We can use this feature to create tuples and closures that look like types, or we can use them to provide alternative names for existing objects. In this post, we'll look at five ways in which typealiases can help you write cleaner and better code.

1. Improving readability with type aliases

Perhaps this is the most obvious yet also somewhat underused way to use a typealias. When you have a type in your code that is very long or deeply nested, you could end up with rather long type declarations.

The following code snippet is an example of a rather long type name:

UICollectionViewDiffableDataSource<CardSection.Diffable, Card.Diffable>

I have made the previous declaration nice and long on purpose, but it's not far from code that I have actually written. You can make the type declaration above much shorter with a simple typealias:

typealias CardDataSource = UICollectionViewDiffableDataSource<CardSection.Diffable, Card.Diffable>

After defining this in your code, the Swift compiler will now know that whenever you write CardDataSource, you really mean UICollectionViewDiffableDataSource<CardSection.Diffable, Card.Diffable> instead. This is really neat because instead of writing the same long, hard to read type declaration over and over, you can instead use the shorter, more descriptive type alias you created.

The same idea can be applied to functions that take a completion closure:

func fetchCards(_ completion: @escaping (Result<[CardSection], Error>) -> Void) {
  // implementation
}

While the code above isn't horrible, we can make it a bit more readable with a typealias:

typealias FetchCardsHandler = (Result<[CardSection], Error>) -> Void

func fetchCards(_ completion: @escaping FetchCardsHandler) {
  // implementation
}

Reading this alternative function that uses a typealias is easier on the eyes since there is much less information to unpack in the function declaration. On the other hand, if someone is trying to figure out what the FetchCardsHandler is they will need to dig a little bit deeper than they would if the function directly exposed the closure's type signature. I'll leave it up to you to decide whether you prefer typealias or closure signatures in your functions since you could argue for either and make a compelling case in my opinion.

As you've seen in this first type, typealias can improve readability but in some cases they can hurt discoverability. In the case of the diffable data source typealias, this isn't much of a problem. In the closure case, this can be a bit more problematic. As with any technique, always consider your options carefully and when in doubt favor clarity and obviousness.

2. Communicate intention

A well-placed type alias can help developers determine what valid inputs for a certain method are, or what the inputs are used for. A good example is the TimeInterval alias that's used on iOS. Whenever you see that a certain method or property has the type TimeInterval you immediately get a sense of what kind of inputs you can use, and what will be done with them. Internally, however, a TimeInterval is nothing more than a typealias.

Another example of a type alias that communicates an intention to the user is a special ID type that's used inside of a struct:

typealias ID = Int

struct Card {
  let id: ID
  // more properties and code
}

struct CardSection {
  let id: ID
  // more properties and code
}

In the preceding snippet, you can see that the Card and CardSection objects both have an id property who's type is ID. While this doesn't look that impressive, it's pretty neat. We can now enforce that Card and CardSection use the same type as their ID by ensuring that they both use the same aliased type. In this case, both identifiers have to be integers. This can provide a lot of meaning to other developers reading this code and when used carefully can really make a big difference in your code.

3. Combining protocols

This is possibly one of the more interesting and obscure ways to use a typealias that I actually use regularly myself. I even wrote an article about it a while ago so I won't go in-depth too much. In Swift, you can use a typealias to create a placeholder for something that conforms to one or more protocols. For example, you can do the following:

typealias CommonDataSource = UICollectionViewDataSource & UITableViewDataSource

The result of the code above is that any object that claims to be a CommonDataSource must conform to both UICollectionViewDataSource and UITableViewDataSource. Since this example is cool but not very useful, let me give you another brief example:

public typealias Codable = Decodable & Encodable

Does the above look familiar? The idea of it probably does! If you declare a type to be Codable, it's both Encodable and Decodable. The way this is defined in Swift is through a typealias that looks exactly like the one in this code snippet.

4. Named tuples

In Swift, we can define something called a tuple. A tuple is a set of values that are grouped together. For example, take a look at the return type of the function below:

func divide(_ lhs: Int, _ rhs: Int) -> (result: Int, remainder: Int) {
  return (lhs/rhs, lhs % rhs)
}

The code above returns a pair of values from a function called divide. Instead of defining a struct or class to hold the two values that we'd like to return we can return a tuple of values which can be quite convenient for cases like this.

Since a tuple's definition on its own doesn't always tell us much about what the tuple represents, we can use a typealias to give a name to this tuple to make its intent clear:

typealias DivisionResultAndRemainder = (result: Int, remainder: Int)

func divide(_ lhs: Int, _ rhs: Int) -> DivisionResultAndRemainder {
  return (lhs/rhs, lhs % rhs)
}

Users of this code now understand what the returned tuple is, and how they can use it.

An interesting side effect of using tuples and type aliases like this is that you could even swap out the DivisionResultAndRemainder tuple for a struct with the same properties without making any changes to callers of divide(_:_:) which is pretty neat.

5. Defining a protocol's associated type

The fifth and last tip is a more advanced one that is used a lot in the Swift source code. Sometimes a protocol has an associated type:

protocol Sequence {
  associatedtype Element
  associatedtype Iterator: IteratorProtocol where Iterator.Element == Element

  // more code...
}

Note:
If you're not familiar with associated types or if you want to learn more, I recommend that you read the following posts on this topic:

The Swift compiler is usually pretty good at inferring what the concrete types of these associated types should be. However, this can be rather confusing, especially if the associated type is used in more than one place. The most common use of type aliases in the Swift standard library is (by far) the explicit definition of associated types:

extension ClosedRange: Sequence where Bound: Strideable, Bound.Stride: SignedInteger {
  public typealias Element = Bound
  public typealias Iterator = IndexingIterator<ClosedRange<Bound>>
}

The code above is directly from the Swift standard library. It shows how ClosedRange conforms to Sequence under certain conditions, and in the extension body, the Element and Iterator associated types from Sequence are defined. What's really interesting is that all Sequence functionality can now be assigned to ClosedRange through extensions on Sequence rather than explicitly defining them on ClosedRange.

This a great example of how protocol-oriented programming works in Swift, and it's made possible by typealias! Pretty cool, right?

In Summary

In today's quick tip you learned about five different use cases for the typealias keyword in Swift. Some of these use cases can significantly improve your code's readability while others have a more minor impact. You even learned that typealias is used to power large parts of the Swift standard library and that without typealias, protocol-oriented programming probably wouldn't look like it does today.

If you have more cool uses of typealias to improve your code, if you have questions or feedback, don't hesitate to send me a Tweet.

Reversing an Array in Swift

You can reverse an Array, and any other Collection in Swift using the reverse method. For example

var input = [1, 2, 3]
print(input) // [1, 2, 3]
input.reverse()
print(input) // [3, 2, 1]

The code above takes an array (input) and reverses it in-place using the reverse() method. This only works if your array is mutable.

If you want to reverse an immutable array that's defined as let, or if you don't want to alter the original input you can use reversed() instead of reverse():

var input = [1, 2, 3]
print(input) // [1, 2, 3]
var reversed = input.reversed()
print(input) // [1, 2, 3]
print(reversed) // ReversedCollection<Array<Int>>(_base: [1, 2, 3])

The reversed() method returns an instance of ReversedCollection. It can be used much like a regular Collection and you can convert it to a regular Array as follows:

let reversedArray = Array(reversed)
print(reversedArray) // [3, 2, 1]

It's typically advised to avoid making this final conversion because ReversedCollection doesn't compute the reversed array unless absolutely needed. Instead, it can iterate over the input array from the end to the start which is more efficient than reversing the entire array all at once. So only convert the result of reversed() to an Array explicitly if you run into problems otherwise which, in my experience, is almost never.

Year in review: 2019

It's the end of the year, and that means that we should all take a little bit of time to reflect on the past year. Some people like to reflect on their past year in a very statistical manner, they set measurable goals and they decide whether they met their goals at the end of the year. Personally, I don't really set goals per year. I simply strive to do the best I can every year. In this post, I would like to reflect on how 2019 has been for me, and I will share some of my plans for 2020 with you.

Recapping 2019

Right of the bat, 2019 was an interesting year for me. In January, I first attended dotSwift in Paris which was an amazing experience. I went to the city a day early with my girlfriend, Dorien, and we caught a concert by one of my favorite bands of all time called Architects. Paris is a beautiful city and since the conference only lasts half a day, we had plenty of time to walk around the city. After the conference, I met up with Dorien and we ran into several other people who we ended up having an amazing dinner with.

Shortly after attending dotSwift I went to Romania to speak about designing frameworks that work on multiple platforms at MobOS. The conference was amazing and I got to meet several amazing people, including Benedikt Terchete, Dave Verwer, Paul Hudson and others. When the conference was over, we went to a salt mine which was a beautiful experience and tons of fun!

A couple of weeks after delivering my framework design talk at AppDevCon in my (almost) hometown Amsterdam. At the pre-conference dinner, I met Kaya Thomas, which was really cool.

A couple of days after I spoke at AppDevCon, I got on my first ever intercontinental plane ride to Tokyo because I was invited to speak at try! Swift in Tokyo where I finally met my friend Jon-Tait after we'd been hanging out online for years! I also met a new friend at try! Swift, Nic Laughter. And of course, I met many other wonderful people too, like Natasha, Mayuko and Kristina. If you ever want to visit a conference that will blow your mind, I can recommend try! Swift Tokyo. The city is beautiful and the conference is put together so well. It's truly awesome.

After returning from Tokyo, I went to New York for the first time in my life for a couple of days in April. I went there to work for a couple of days, so, unfortunately, I didn't see much of the city. And I left my wallet on the airplane when I arrived so that wasn't great. Luckily, I came back to the United States a month later for WWDC so I got a retry in experiencing what the US is like, with the added benefit of it being at WWDC.

If you ever get a chance to visit San Jose during WWDC week, I recommend you do. I had a ticket for the conference this year which made the experience even better but I'm sure I would've had an amazing time without a ticket too. There are so many amazing people in the area during the week of WWDC, and the parties and gatherings of people are so much fun. The best part is that AltConf is right next door, so you can even attend a conference while you're there. Speaking of AltConf, I snuck out of WWDC for a moment to attend a talk my friend Nic gave called The Hidden Potential of People with ASD. I really enjoyed and you should definitely check it out if you want to learn more about autism in the workplace.

About a month after returning from WWDC I was lucky enough to attend Swift Island which, according to the Hacking with Swift community awards was the best conference of the year this year! So I was truly lucky indeed. I had a great time there and if you're ever looking for a conference that has a vacation-vibe going on, make sure to go to Swift Island.

After Swift Island, I was a guest on the iPhreaks podcast where we discussed Core Data. After that, I didn't do much until September. In September I started blogging again and I wrote a couple of posts about testing. Coincidentally, I had the opportunity to speak about testing at MobiConf in Krakow, Poland in October. Going to Poland was tons of fun, especially when I found out my friend Antoine was speaking too! At MobiConf I met several old friends, but I also made new friends and wanted to mention Aleksandra, Vadim and John in particular. Aleksandra and Vadmin, it was awesome to spend a couple of hours exploring Krakow with you before I went to the airport. And John, thanks for showing me and the gang around in Krakow's food and cocktail scene. It was a blast!

Days after I got home from Modbiconf I was invited to speak at GDG Coimbra in Coimbra, Portugal. This was another fun conference where even though I was pretty much the only iOS developer, I met awesome people. I wanted to give a special shoutout to Ivan, your talk was super funny and it was fun sitting with you at the speaker's dinner. It was also a ton of fun to meet Eugenio and I met up with Fernando who I had first met at MobiConf. Small world, right?

In December I didn't do any speaking. Instead, I worked on a project called Advent of Swift where I published one article on this blog every day. The project was a ton of fun and it brought me some very cool side-effects. For example, I was a guest on both Contravariance and Swift by Sundell. And I was chosen as the winner of the Rising Star category in the Hacking with Swift community awards. To wrap up the month of December I launched the Advent of Swift bundle which contains all Advent of Swift articles and several sample projects. It's available on Gumroad for just $1,99.

Wow. Summing my year up like this really confirms what I have been saying all along. It's been a wild year! Not just for the iOS community with SwiftUI, Combine, Xcode 11 and iOS 13, also for me personally! And a lot of this wouldn't be possible without the iOS community, all the amazing conference organizers and the amazing speakers that travel the world to talk at all the conferences.

In addition to all these people, it's also not possible without you specifically. Yes, you, the person reading this. If you wouldn't visit my website and read my articles, the last three months of this year wouldn't have been as exciting as they were, and all I can do is thank you from the bottom of my heart.

Looking ahead: 2020

No year in review is complete without at least mentioning the year after. I already mentioned that I don't do goals for the new year. But I can tell you that I plan to speak at conferences again in 2020, and I have already submitted several papers to CFPs. I can also tell you that I'm going to continue to bring you content in 2020 and for the foreseeable future I'm going to keep going with my two posts a week schedule. I enjoy that schedule and I hope you do too. And of course, I'm already thinking about what kinds of cool extra projects I can do for my blog in 2020.

I hope to see you again in 2020, and I wish you all the best and a Happy New Year!

Getting ready to publish your app on the App Store

You've done all the work to build your app, your UI looks amazing, animations are smooth and you're ready to put your app in the hands of other people. Maybe you're even ready to start offering your app on the App Store! This is a huge achievement if you are currently at this stage in your development cycle, I would like to congratulate you. Being ready to ship your app is a huge accomplishment, especially if it's your first App. I still remember the excitement when I submitted my first app to the App Review team in App Store Connect (when it was still called iTunes Connect). And I was even more excited when the app got approved and I could tell my friends to search for it in the App Store, and they would find it and download it. That truly was a magical moment for me.

Today, I would like to share some tips that will help you get ready for a smooth launch of your app. I am by no means a marketing expert, so I won't give you advice on how you can promote or market your app. Instead, I will provide you with a list of things you'll need to do from the moment you decide you're ready to push your app up to App Store Connect and submit it to the App Store. By the end of this post, you will know how to create your app in App Store Connect, how to submit your app for beta testing and even how to submit your app for App Store review.

The list below is presented in an order that I find comfortable, but of course, you're free to follow the steps in any order that fits your workflow.

Review the guidelines

Ideally, you execute this step early in the development process of your app. If you're not familiar with Apple's App Store Review Guidelines, you can find them here. This document contains loads of information that you need to know to make sure your app is appropriate for the App Store. For example, the guidelines state that your app must contain functionality that makes it interesting or more than just a website packaged in an app. Unfortunately, reviewing the guidelines is not a guarantee that your app will be accepted in the App Store. The review process is conducted by humans that might interpret the guidelines slightly different than you did. Regardless of this fact, it's still a good idea to familiarize yourself with the guidelines because it prevents a lot of disappointment down the line.

Create your app in App Store Connect

Before you can submit your app to the store, you must register it on Apple's App Store Connect platform. App Store Connect is the central place where you manage your entire app's store presence. To register your app, log in and on your dashboard click the My Apps icon. Next, click the + icon in the top left corner of the screen to add a new app. Fill out the form that pops up:

Register App Pop Up

Your app's bundle identifier might not be present in the list of bundle ids that are presented in the drop-down menu for the Bundle id field. If this is the case, click the Certificates, Identifiers & Profiles link that is shown below the drop-down and fill out your app's information to register your bundle id in the developer portal:

Registering an app in the developer portal

Once you've registered your app, you are taken to your app's management portal. Here you can manage your app's App Store information, pricing and the builds that you're running in Testflight or submit a new build for review.

Note that you can localize the information that's shown under the Localizable Information header using the drop-down menu on the right side of the window. When you registered your app, version 1.0 was created for your app in the sidebar on the left. This is where you can add screenshots, videos and release notes for your app's version. This is also where you select the build of your app that you want to submit to the App Store. But before you can do this, you need to archive your app in Xcode and upload it to App Store Connect.

Archive your App in Xcode and upload it to App Store Connect

Once your app is ready to be deployed to App Store Connect, you need to archive it. To do this, select the Generic iOS Device as the target to build your app to, and select the Product -> Archive option from the Xcode menu bar:

Archive app

Archiving your app might take a little while because Xcode will build your app using your Release configuration, and using settings that will allow your app to run on all iOS devices. When Xcode is done archiving your app, the Organizer window will open. From there you can select the archive that Xcode just created for you, and you can upload it to App Store Connect using the Distribute App option. Typically, you can keep al default options and click Next for every step. Once you've gone through all the steps, Xcode will upload your app to App Store Connect where your binary will be processed. This might take a while and you should receive an email from Apple when your binary has completed processing.

Deploy your app to TestFlight

Once your build has processed, you need to prepare it for Testflight. Fill out all the required information under the Test Information section on the Testflight page for your app. You also need to provide "compliance information". Click on the warning sign that should be visible on your processed build and provide the requested information. Once you've done this you can immediately send your Testflight app to your App Store Connect team members using the App Store Connect Users section in the sidebar.

To send your app to external testers, go to the Add External Testers page in the sidebar. You will first be asked to create a group for your testers. Provide a name and continue. Next, go to the Builds section on the external testers page and add the build that you just uploaded.

Uploaded app build in AppStoreConnect

Follow the steps in the pop up that appears after you've clicked the Add build to start testing button. Make sure to fill out the Test Information page with the key parts of your app that you want your testers to pay attention to. After doing this, click Submit for Review. This will send your app to Apple for a very brief beta-phase review. Getting approved for Testflight does not guarantee that your app will be approved for the App Store. In the meantime, you can begin adding testers using the Testers section. Once your build has been approved by Apple, a public link will be visible on the Testers page that you can share to allow people to obtain access to your Testflight app.

Create a video of your app's key features

The App Store allows you to include a video that promotes your app on your App Store page. While this is not required, it's certainly recommended. Your promo video should be short, to the point, and it should make people want to use your app. It's important to ensure that your video doesn't rely too much on Audio because not everybody that uses the App Store will be in a position to listen to your promo video's audio. Again, a promo video is not required but it's most certainly recommended.

Create screenshots for your app

While a promotional video is optional, screenshots are required. When supplying screenshots for iPhone, you need to upload screenshots for, at least, the 6.5" Display form factor and the 5.5" Display form factor. This boils down to the largest phones with, and without a home button. Smaller form factors will use the larger screenshots on the App Store page. Of course, you're free to upload screenshots for every display size individually if you want to. For iPad, you need to include screenshots for the 12.9" 2nd- and 3rd generation iPad pros. Again, this boils down to devices with and without a home button. The larger form factor screenshots will be used for the smaller displays on the iPad in the same way this is done for the iPhone.

It's possible to localize your screenshots similar to how you can localize your app's information on the App Information page.

When you need to take screenshots for several devices, using many different localizations, I can recommend that you look into using Fastlane. Fastlane includes a tool called Snapshot that allows you to automate the process of taking screenshots using UI Tests which is really convenient. I won't go into detail about setting this up since that topic should be an entire post of its own.

Prepare your app's metadata in App Store Connect

Once you're happy with the results of your Testflight beta, everything is prepared and uploaded and you're feeling confident to send your app to the review team you should give your app's metadata one last look. Make sure your app name is correct, add a privacy URL and a catchy subtitle and pick the primary and secondary category that your app should be listed in. Additionally, on the version-specific page, make sure that you include a nice promo test and an accurate description of your app. For your keywords, it's important to try and use as many relevant keywords as possible. Don't include your app name in the keywords because your app will already be indexed using your app name.

Also, make sure to select the correct build under the Build section, include a nice App Store icon (this should be your app icon exported at 1024x1024 pixels) and add any other relevant information.

Once everything is set, it's time to take the final step; Submitting to the App Store

Submit your app for review

When you submit your app for review, you can still change some of your app's metadata but keep in mind that a lot of the information about your app cannot change anymore. Also, make sure to check the appropriate way to release your app.

Selecting a release method in AppStoreConnect

If everything is in a good place, and your happy with your app, your App Store description and other metadata and you've selected an appropriate way for your app to be rolled out to users once it's approved, click the big Submit for Review button on your app's version page.

Rejoice!

After submitting your app, the waiting game begins. Apple will typically review your app within a couple of days but it might also take a few hours or a week. The key is patience. If your app has been in review for over a week, it might help to re-submit your app. But often, waiting a bit longer is the better strategy. If Apple rejects your app, the rejection notice will typically include a little bit of information about the reason. Often they will include the App Store guideline that they consider you to break, and you should correct this. If you don't agree with the verdict, you can always appeal or request a call with Apple. Keep in mind that Apple is not your enemy here, they will happily work with developers to help them make the required adjustments and get you in the store. Their main priority is to make sure everything that's published in the Store is up to their standards. Unfortunately, this is a process performed by humans and some reviewers appear to be more strict with certain guidelines than others. There's nothing you can do about that other than trying to work with your reviewer to resolve any issues.

Once your app is approved, it's time to celebrate! Tell all your friends and most importantly, send me a Tweet! I want to see your finished projects in all their glory.

Dependency injection with Storyboards and Xcode 11

For years I have had a bit of a love and hate relationship with Storyboards. I love how easy they make it for me to set up my AutoLayout constraints, but they can quickly grow unwieldy and for large projects with multiple developers Storyboards are hard to use because of merge conflicts that occur when multiple developers update the UI. For personal projects, however, my Storyboards tend to be small enough to manage. And since I'm the only developer working on them I never have merge conflicts. Yet still, I've never been completely happy with them.

The main reason for that is that Storyboards used to make it impossible to use dependency injection. So what you end up with is a view controller with tons of optional properties that you have to set in prepare(for:sender:) when a segue is about to be performed. That all changed with Xcode 11 and iOS 13.

In today's article, I will show you how you can use the new @IBSegueAction attribute and the Instantion segue action to add proper dependency injection to your Storyboard based view controllers.

Understanding the problem that @IBSegueAction solves

The following code should look familiar to anybody who's used storyboards before and had to pass data from one view controller to the next:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  switch segue.identifier {
  case "ShowDetailPage":
    guard let indexPath = collectionView.indexPathsForSelectedItems?.first,
      let detailViewController = segue.destination as? DetailViewController else {
      break
    }

    detailViewController.item = viewModel.item(for: indexPath)
  default:
    break
  }
}

The problem with this code is that it's fiddly and the DetailViewController needs to have multiple optional properties while they really shouldn't be. In the example above, the DetailViewController needs an item to display. If no item exists, it makes no sense to display the view controller. In fact, we really want to enforce this on a compiler level; we shouldn't be able to create an instance of DetailViewController if we don't have a selected item.

Unfortunately, the only way to enforce something like this at the compiler level has always been to ditch storyboards and to manually instantiate your view controllers. This is far from ideal and is the main reason that I've been avoiding Storyboards in my projects. Luckily, Xcode 11 and iOS 13 introduced a new feature that resolves this problem. It's called @IBSegueAction.

Using @IBSegueAction in an app

When you use @IBSegueAction, your Storyboard can defer the creation of a destination view controller to you entirely. This means that you are able to create an instance of the destination view controller and inject any required dependencies directly. In other words, you regain full control over how an object is initialized and what dependencies it has. Let's look at an example:

@IBSegueAction
func createDetailViewController(coder: NSCoder, sender: Any?, segueIdentifier: String?) -> DetailViewController? {
  guard let indexPath = collectionView.indexPathsForSelectedItems?.first else {
    return nil
  }

  return DetailViewController(coder: coder, item: viewModel.item(for: indexPath))
}

Every segue action you define can be named however you please. I chose createDetailViewController for my action name, but you can pick any name you want. It also must accept three parameters: coder: NSCoder, sender: Any? and segueIdentifier: String?. The return type of the action is always an Optional<UIViewController> or UIViewController?. You should substitute UIViewController with your own view controller subclass.

In the body of your action @IBSegueAction method, you create the view controller that should be used as the destination of the segue that the action belongs to. Since Storyboards use the required initializer init?(coder: NSCoder), the coder must be passed along to the target view controller's initializer.

Let's have a look at DetailViewController now to see what it's initializer looks like:

class DetailViewController: UIViewController {
  let item: DetailItem

  required init?(coder: NSCoder, item: DetailItem) {
    self.item = item
    super.init(coder: coder)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

The definition for DetailViewController now has an initializer that accepts the DetailItem. And because we can assign the item property during initialization, it doesn't have to be optional. And because we don't want anybody to initialize the DetailViewController without a DetailItem, the default initializer contains a fatalError. This will enforce that we can only initialize this view controller with the init?(coder:item:) initializer.

Since @IBSegueAction works slightly different for regular segues than it does for relationship segues I will explain each separately in the next subsections.

Using @IBSegueAction with a regular segue

When you're using a regular segue in your Storyboard, for example when you navigate from a table view to a detail page, you can create your Segue like you normally would by ctrl+dragging from your table view cell to the destination view controller. After doing this, click the segue and give it a Segue Identifier. So far, nothing special. If you use Storyboards regularly you have done this many times before.

Next, open the Connections Inspector and behold. There's a new option:

new Segue option

The Connections Inspector now contains an Instantiation connection for segues. Drag from the circle to the view controller that implements the @IBSegueAction for the target view controller that your segue points to. When you use it to navigate to a detail view controller, you will typically want your list view controller to be the target. When you release your drag action on the correct view controller, you will see the option to pick an appropriate @IBSegueAction method. You can use the same method for multiple segues, and you can have multiple @IBSegueAction methods for one view controller.

After connecting the Instantiation action, there's nothing else for you to do. If you run your app, your segue action will now be called whenever the segue it's attached to is called.

Using @IBSegueAction with a relationship segue

While regular master -> detail segues work pretty reliably, there seems to be something strange going on for relationship segues. A relationship segue is a connection between a navigation controller and its root view controller. Or the connection between a tab bar controller and its view controllers.

When you execute a segue where you present a navigation controller with a root controller modally, it's possible to use an @IBSegueAction to configure the navigation controller's root controller. The way this works is a little bit counter-intuitive though. Imagine an app where you have the ability to add items to a list:

Screenshot with Add button

If you tap the add button in the app from the screenshot above, a modal view controller is presented. The view controller is contained in a navigation controller so we can add a Save and Cancel button in the view controller's navigation item.

When you want to use an @IBSegueAction for the view controller, you should add the action to the list view controller. When you connect the Instantiation action, Interface Builder will automatically move the connection from your list view controller to the navigation controller. Don't be fooled however, at runtime, the system will look for the @IBSegueAction on the list view controller. This is even the case if you add the @IBSegueAction to a navigation controller subclass. No matter what you do, the system will look for the segue action on the source of the presentation. This has definitely cost me an hour or two to figure out so keep this in mind.

In Summary

Today, you've learned that with Xcode 11 and iOS 13 you can finally implement proper dependency injection when using Storyboards. You saw what the problem is with the old state of affairs, and how the new @IBSegueAction makes everything better. You also saw how to set up segue actions in Interface Builder connecting the Instantiation action to your @IBSegueAction methods. And to wrap it up, you learned about a strange little quirk that you might encounter with modal presentations and relationship segues.

I'm certainly going to give storyboards another chance in the coming months because I think this new feature looks very promising. What are your thoughts? Does this convince you to give Storyboards another try? Let me know on Twitter.

Using compositional collection view layouts in iOS 13

Ever since iOS 6, developers have been able to use collection views and to build interesting custom layouts by subclassing the UICollectionViewLayout or UICollectionViewFlowLayout classes. I even wrote an article about building custom collection view layouts a while ago. Today, I would like to introduce you to a new way of defining collection view layouts called compositional layouts. We're going to build the two layouts shown in the following image:

Designs for the collections

I will first show you how to build a simple grid layout, and from there we'll continue working our way towards the end result.

Building a grid layout

A very common use of collection views is to display a grid layout. It's so common that Apple has included a grid layout called UICollectionViewFlowLayout with iOS since they introduced UICollectionView in iOS 6. Since it's such a familiar and relatively simple layout, I want to explore the basics of UICollectionViewCompositionalLayout with you by using it to build a grid. I'm going to assume that you have already got a collection view setup, possibly with a diffable data source. If you want to follow along with the code samples in this post, I would recommend that you always put your compositional layout code in a method, as I will soon demonstrate. You can then assign the layout to your collection view by writing the following in your viewDidLoad() method:

collectionView.collectionViewLayout = createCompositionalLayout()

Before I explain the anatomy of a compositional layout in detail, let's dive right in with an example:

func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
  let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5),
                                       heightDimension: .fractionalHeight(1.0))
  let item = NSCollectionLayoutItem(layoutSize: itemSize)

  let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                        heightDimension: .fractionalWidth(0.5))
  let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

  let section = NSCollectionLayoutSection(group: group)

  let layout = UICollectionViewCompositionalLayout(section: section)
  return layout
}

If you examine the preceding code upward from the return statement, you will notice that the UICollectionViewCompositionalLayout initializer takes an instance of NSCollectionLayoutSection. In other words, a layout is built using sections. These sections are built using NSCollectionLayoutGroup instances. A single section can contain multiple groups, and as we'll see in the final section of this article, a section can also contain several different groups. Groups are considered to be the biggest workhorse of a compositional layout. You will typically do most configuration work on groups.

Notice that the example code uses NSCollectionLayoutGroup.horizontal to create the layout group. By making the layout group horizontal, all items that are added to the group will be positioned horizontally. This means that the group will position items on the horizontal axis until it has filled up its width, and then it starts positioning items on the next "line" until that contains as many items as can be fit in the group's width and so forth. We also pass the group one or more item configurations. In addition to items, a layout group also receives a size. In the example code, we use a fractional size. You might notice that I've used fractionalWidth for both the heightDimension and the widthDimension. The reason for this is that I want the grid to contain square items. To achieve this, I defined a group that takes the full width and is as tall as half of the screen width. If you now look at the declaration of the NSCollectionLayoutItem that is passed to the layout group, you'll see that an item has a fractional height of 1, and a fractional width of 0.5.

In other words, the layout group defined in the code above will fill the full width of its container and its height will be half the width of its container. The items inside of the group will all take up half the width of the container, and its full height, which makes the cells in the grid squares. The following image shows items, groups, and sections in an example grid layout.

Layout components

In addition to a fractional width and height, you can also assign an absolute size using .absolute(240) which would make an item exactly 240 points wide or tall, or you can use .estimated(240) to let the system decide the optimal height for an item based on its contents.

If you would assign the layout that's generated by the createCompositionalLayout() method I just showed you to a collection view's collectionViewLayout property, you would get a very similar looking grid as a result. The items are a bit cramped though, so let's explore some of the spacing options we have.

Adjusting the spacing between items, groups, and sections

There are two possible ways to give your collection view cells some room to breathe:

  • Assign edge insets on the items, groups or sections.
  • Assign a spacing between individual items and groups.

When you assign edge inserts to an item, its size doesn't change. Examine the following image:

Individual item with insets

The red box around the gray square is the item's bounding box. It takes up the space that's defined by the item's NSCollectionLayoutSize. The insets are applied inward from that bounding box, and the cell is eventually rendered in the remaining space; the gray area in the above image. You can assign edge insets on an item using the following code:

item.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)

Try adding this line of code to the grid layout you've defined earlier and notice how it gives a nice spacing between cells.

It's also possible to apply insets to groups. The insets that you apply to groups follow the exact same rules as insets that are applied to items. The following image illustrates this nicely:

Group with insets

The gray squares are the rendered cells, the red lines are the bounding boxes for the items, and the blue lines indicate the bounding box for the layout group. And like items, this blue bounding box will have the size that you specify for the group itself, and the insets are applied inwards.

Lastly, you can apply insets to sections. Sections follow the same rules as groups and items, and their insets stack on top of the insets defined on items and groups:

Section with insets

The only difference is that sections always take up the full width of the viewport, and their height is always determined dynamically.

In addition to insets, you can specify how spacing should be applied between items and groups. Spacing is always applied to the bounding box of one element to the next as shown in the following screenshot by the red spacing indicator. Items are shown on the left, groups are shown on the right.

Spacing example

You can apply item and group spacing using the following code:

// item spacing
group.interItemSpacing = .fixed(15)

// group spacing
section.interGroupSpacing = 15

Note that we define item spacing on the group that contains the items, and group spacing on the section that contains the groups. And also note that the item spacing is defined as .fixed(15) in this case. This means that groups will always position their items with 15 points between them. You can also use .flexible(<spacing>) to allow the group to determine the best spacing between items based on its size, and the size of the items that it's positioning. The group will use the value of its flexible spacing as the minimum spacing between items; your items might be positioned further apart from each other than you specified, but never closer to each other.

I highly recommend using the simple grid layout I shared at the start of this section to explore the inset- and spacing options I've described in this section. A grid layout is simple and predictable which makes it a perfect candidate for exploration of options.

Adding section headers to a layout

At the beginning of this article, I told you that I would show you how to build two different layouts. One of these two layouts contains section headers. So let's see how you can add section headers to your compositional collection view layout. If you're following along with the code I'm presenting in this article, you can use the following code snippet in the context of your grid layout, or any other compositional layout you might already have:

let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "header", alignment: .top)
section.boundarySupplementaryItems = [headerElement]

The first line of the preceding snippet should look familiar to you. The size of a collection view header is defined in exactly the same way as the size for items and groups. The header is defined as an instance of NSCollectionLayoutBoundarySupplementaryItem. Headers and footers are both different types of supplementary views, so they are defined in the exact same way. Depending on the value you pass to the alignment argument in the NSCollectionLayoutBoundarySupplementaryItem initializer, the supplementary view will act as a header, footer or just a decorative view. Also, note that there is an elementKind argument. This argument is a string identifier, similar to a cell reuse identifier that you use in your collection view data source when it's asked to provide a supplementary view.

Note:
Since this post is not about setting up a collection view data source, I'm not going to explain section headers in depth. In short, you need to implement the collectionView(_:viewForSupplementaryElementOfKind:at:) method from the UICollectionViewDataSource protocol. You also need to register a UICollectionViewCell subclass on your collection view using the collection view's register(_:forSupplementaryViewOfKind:withReuseIdentifier:) method. This method is very similar to registering a collection view cell in code, except you also supply the element kind string identifier.

Amazingly, the code above is all you need to add section headers to your layout. The following image shows our progress in implementing the layout from the beginning of this article:

Grid with a section header

Building a layout that scrolls on both axis

Now that we have a basic grid with section headers to work off, let's implement the first collection view layout by changing just a couple of lines of code.

The first change to make is to reconfigure the groups in the grid layout a little bit. We'll make items inside of groups take up the entire space of the group, and we'll update the group so it takes up roughly 90% of the available with, and the group's height will be relative to the available width to make the group size (and item size) a size that is based on an aspect ratio:

let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)

let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .fractionalWidth(0.5))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

If you compare the code above to the grid code we had before, you'll notice that you only changed a couple of numbers. If you run your app with these changes, you should now have a layout with a section header where each cell takes up almost all width, and they are all stacked vertically as shown in the following image.

Full width items with header

Let's make some more changes to make the items in a section appear next to each other so we can scroll through each section on the horizontal axis:

let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
section.interGroupSpacing = 16
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)

The key line in the preceding snippet is section.orthogonalScrollingBehavior = .continuous. By assigning a value to the orthogonalScrollingBehavior property on a section, you flip everything on its head. The section will now place groups next to each other rather than on top of each other. And since every group in our layout contains a single item, we end up with a carousel that matches the design from the beginning of this post. Amazing, isn't it?

The orthogonal scrolling option that I chose in the preceding example is .continuous. This option will make each section scroll like a plain scroll view. The user drags their finger over the screen and the section scrolls. Other values for this option are .continuousGroupLeadingBoundary, .paging, .groupPaging, .groupPagingCentered and more. Some of these options implement a paging behavior, and others manipulate how a section responds when it's scrolled in more subtle ways. I can absolutely recommend that you take the examples from this article and play around with the different behaviors because they are tons of fun to mess around with.

That wraps up the first collection view layout I wanted to show you! We began with a simple grid, and by changing a couple of numbers, adding a header and setting a property on our sections, we now have a layout that can scroll horizontally and vertically. It's truly amazing how little code we needed, especially when compared with the code we would have to write without compositional layouts.

Creating an advanced grid

At the start of this article, I showed you a second grid layout. This layout is interesting because in order to build it we must use nested groups. When using a compositional layout, you can pas more than one item to an NSCollectionLayoutGroup's subitems array. When you do this, the group will use all items in order for the layout. So when you pass two items, the group will use the first item for the first cell it contains, the second item for the second cell and then the first item again for the third cell and so forth.

In our case, we want to create one regular item for the full-width cell, and then a nested group that contains two half-sized items for the two smaller cells that are positioned below the wide cell. The following code can be used to create the layout we're looking for:

func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
  let inset: CGFloat = 8

  // Large item on top
  let topItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(9/16))
  let topItem = NSCollectionLayoutItem(layoutSize: topItemSize)
  topItem.contentInsets = NSDirectionalEdgeInsets(top: inset, leading: inset, bottom: inset, trailing: inset)

  // Bottom item
  let bottomItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0))
  let bottomItem = NSCollectionLayoutItem(layoutSize: bottomItemSize)
  bottomItem.contentInsets = NSDirectionalEdgeInsets(top: inset, leading: inset, bottom: inset, trailing: inset)

  // Group for bottom item, it repeats the bottom item twice
  let bottomGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalWidth(0.5))
  let bottomGroup = NSCollectionLayoutGroup.horizontal(layoutSize: bottomGroupSize, subitem: bottomItem, count: 2)

  // Combine the top item and bottom group
  let fullGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(9/16 + 0.5))
  let nestedGroup = NSCollectionLayoutGroup.vertical(layoutSize: fullGroupSize, subitems: [topItem, bottomGroup])

  let section = NSCollectionLayoutSection(group: nestedGroup)

  let layout = UICollectionViewCompositionalLayout(section: section)

  return layout
}

I added some comments to the code. All of this should look familiar to you, it's mostly just a different way of composing the elements you have learned about in this article. This familiarity is exactly what makes compositional layouts so powerful. It doesn't matter whether you want to build something simple like a grid, or something more complex like we just did, you always use the exact same components composed in a different way. Cool, right?

In summary

Today's article introduced the new UICollectionViewCompositionalLayout class. You learned that this class allows you to specify complicated collection view layouts using four simple building blocks; items, groups, sections and the layout itself. With these blocks you can build layouts that would be a nightmare to implement using the good old UICollectionViewFlowLayout and the code to do this is simple and concise.

You saw how to build a collection view layout that positions its sections vertically, and the items within the section can be scrolled through horizontally. You learned that this is called orthogonal scrolling, and it can be enabled with just a single line of code. You also saw how you can nest groups to build a somewhat irregular looking layout that's very interesting visually.

If you have any questions about this article, or if you have built something really cool that with a compositional layout make sure to let me know. I love to hear from you.

Modern table views with diffable data sources

At WWDC 2019 Apple announced a couple of really cool features for table views and collection views. One of these cool features comes in the form of UITableViewDiffableDataSource and its counterpart UICollectionViewDiffableDataSource. These new diffable data source classes allow us to define data sources for collection- and table views in terms of snapshots that represent the current state of the underlying models. The diffable data source will then compare the new snapshot to the old snapshot and it will automatically apply any insertions, deletions, and reordering of its contents.

In today's article, I will show you how to use UITableViewDiffableDataSource to drive your table views. Since the table view data source is pretty much the same as the collection view version apart from some class names, I will focus only on the table view variant. The following topics are covered in this article:

  • Understanding how a diffable data source is defined.
  • Using a diffable data source in your apps.
  • Some best-practices to consider when using a diffable data source.

By the end of this article, you will know exactly how to use diffable data sources and what their caveats are.

Understanding how a diffable data source is defined

A diffable data source is an object that replaces your table view's current UITableViewDataSource object. This means that it will supply your table view with the number of sections and items it needs to render, and it supplies your table view with the cells it needs to display. To do all this the diffable data source requires a snapshot of your model data. This snapshot contains the sections and items that are used to render your page. Apple refers to these sections and items as identifiers. The reason for this is that these identifiers must hashable, and the diffable data source uses the hash values for all identifiers to determine what's changed. Let's look at this a little bit more in-depth by exploring the type signatures of both the data source and the snapshot.

First, let's explore the UITableViewDataSource signature:

class UITableViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType> : NSObject 
  where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

That's quite the mouthful! The UITableViewDiffableDataSource class has two generic types, one for the section identifier and one for the item. Both are constrained so that whatever type fills the generic type must conform to Hashable. If you're not familiar with generics, check out this post I wrote as an introduction to generics in Swift.

It's interesting that Apple has decided to call the data source's generic parameters SectionIdentifierType and ItemIdentifierType. If your data model conforms to hashable, you can use it as the SectionIdentifierType or as the ItemIdentifierType. But, as the name of the generic suggests that might not be the greatest idea. I will explain why in the best practices section. For now, what matters is that you understand that both identifiers must conform to Hashable and that the data source will use hash values to determine changes in your data set.

Now let's look at the second key player in using a diffable data source; the snapshot:

struct NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> 
  where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

The snapshot object is a struct rather than a class, and it has the same generic parameters as the diffable data source it's applied to. This means that you can't apply a snapshot with a set of identifiers to a data source with different identifiers and your code will fail to compile.

Now that you know how a diffable data source is defined, and have a rough idea of how it works, let's get more practical and see how you can use a diffable data source in your apps.

Using a diffable data source in your apps

In this section, I will use a very simple data model where my section identifiers are integers, and my model contains only a title property. In reality, your models will be much complicated than what I'm using here. However, part of the beauty of diffable data sources is that this doesn't matter. Whether your model is simple or more complex, the principles all remain the same.

Setting up the basics

To create a new diffable data source, you create an instance of UITableViewDiffableDataSource as follows:

let datasource = UITableViewDiffableDataSource<Int, MyModel>(tableView: tableView) { tableView, indexPath, itemIdentifier in
  let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)

  // configure cell

  return cell
}

In the preceding example, we use Int and MyModel as the identifiers for the sections and items respectively. We pass the table view that the diffable data source instance should be applied to the initializer of UITableViewDiffableDataSource and we also pass it a closure.

This closure is the cell provider. It's called whenever the table view needs a new cell to render on screen. In many ways, this closure is a replacement for the tableView(_:cellForRowAtIndexPath:) method you might be used to implementing currently. The main difference is that the item identifier that corresponds to the index path for the table view is passed along to this closure. So in the preceding example, you would receive an instance of MyModel as the third parameter for the cell provider closure. This means that if your identifier type contains all properties that are needed to render your cell, you don't have to fetch this object from your underlying data storage anymore.

Let's create a new snapshot that can be applied to our diffable data source:

var snapshot = NSDiffableDataSourceSnapshot<Int, MyModel>()
snapshot.appendSections(storage.sections)

for section in storage.sections {
  snapshot.appendItems(storage.modelsForSection(section), toSection: section)
}

datasource.apply(snapshot)

Note:
The preceding code uses a storage object. It's not a built-in type or anything but rather a placeholder that I made up to use in this example. I'm sure you can derive what this storage object's section property and the modelsForSection(_:) method look like. The main point is that you understand how the snapshot is configured.

The snapshot is created as a var because it's a struct and we wouldn't be able to modify it if we had declared it as a let. First, we call appendSections(_:) on the snapshot. This method takes all section identifiers you want to have present in your table view. Then, we loop through all sections and call appendItems(_:toSection:) on the snapshot. This will associate an array of item identifiers with the section identifier that's passed to this method.

Once all items and sections are added to snapshot, it is passed to the data source by calling apply.

Note that your data source will not update the table view unless you explicitly create a snapshot and call apply to update the table view. If you have already applied a snapshot and want to perform a simple add or remove operation of an item or section, you can get the data source's existing snapshot, modify it, and apply it as follows:

var currentSnapshot = datasource.snapshot()
currentSnapshot.deleteItems([itemToDelete])
datasource.apply(currentSnapshot)

The preceding code takes a snapshot of the data source, deletes an item from it and then applies the snapshot to the data source. NSDiffableDataSourceSnapshot has methods to delete items, sections and even to wipe the entire snapshot clean. If you want to update your data source, it's up to you to decide whether you want to create a new snapshot from scratch or to update the current snapshot.

With a setup like this, you can already provide a table view with data. Let's see how you can add support for section headers and other table view features you might have implemented in the past. For example, cell deletion.

Adding section headers and interactions

Out of the box, the diffable data source is pretty plain. But since it conforms to UITableViewDataSource it can do anything you might be already doing in your current UITableViewDataSource implementation. All you need to do is define your own UITableViewDiffableDataSource and override the methods of features you want to implement. For example, to add section headers you can override tableView(_:titleForHeaderInSection:):

class MyDataSource: UITableViewDiffableDataSource<Int, MyModel> {
  override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return "This is section: \(section)"
  }
}

When you subclass UITableViewDiffableDataSource, you immediately fill in the generic parameters for the section- and item identifiers. In this case, Int and MyModel. Note that the section argument in tableView(_:titleForHeaderInSection:) is not a SectionIdentifierType, instead it's always the integer index of your section. Keep this in mind when you construct your section title. If you would run your app and use this data source subclass instead of the regular UITableViewDiffableDataSource class, you will find that you now have support for section headers.

If you want to add support for deleting items you need to override tableView(_:canEditRowAt:) and tableView(_:commit:forRowAt:) in your data source subclass:

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
  return true
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
  if editingStyle == .delete {
    let model = storage.modelForIndexPath(indexPath)

    var snapshot = self.snapshot()
    snapshot.deleteItems([model])
    apply(snapshot)

    storage.deleteModel(model)
  }
}

Notice how the preceding code finds the model that needs to be deleted in the underlying storage and then updates the existing data source on the snapshot. Finally, the model is also deleted from the underlying storage to ensure that the deletion is persisted.

Best practices for using diffable data sources

During my time exploring diffable data sources, I have run into a problem where I couldn't get cells to reload themselves. Luckily Steve Breen was kind enough to respond to my call for help and I learned a couple of things from him. But even then I was having trouble. Eventually Chris Hinkle came through with an observation. Based on what I've learned I have found two best practices that I think are important to keep in mind.

Keep your identifiers simple and to the point

When you choose your identifiers for your diffable data source and snapshot, try to make sure they only include data that will be rendered or influences the rendering. When I was stuck with reloading my cells, I was using NSManaged object subclasses to drive my data source. This seems to work well enough because everything was there. Items were added, removed and reordered. However, for some reason, my data source never seemed to pick up changes to the properties of my managed objects. I eventually got around this by providing a struct that contained the data I wanted to render rather than the entire managed object. A nice way I've found to define these structs is as extensions on the models themselves:

extension MyModel {
  struct Diffable {
    let id: UUID

    let title: String
    let subtitle: String
    // other properties that will be rendered on the cell

    init(model: MyModel) {
      self.id = model.id
      self.title = model.title
      self.subtitle = model.subtitle
    }
  }
}

When using this approach, you'd replace the MyModel item identifier with MyModel.Diffable, and when you create your snapshot, you must convert all MyModel instances to MyModel.Diffable. Since the initializer for the MyModel.Diffable object takes an instance of MyModel this is fairly straightforward:

var snapshot = NSDiffableDataSourceSnapshot<Int, MyModel>()
snapshot.appendSections(storage.sections)

for section in storage.sections {
  let items = storage.modelsForSection(section).map(MyModel.Diffable.init)
  snapshot.appendItems(items, toSection: section)
}

datasource.apply(snapshot)

By mapping over the array of MyModel objects using the MyModel.Diffable.init, every model object will be passed to the MyModel.Diffable initializer and is converted to an instance MyModel.Diffable. Pretty nifty, right?

Notice that there is one property in my Diffable extension that shouldn't be rendered; the id property. I'll explain why in the next subsection.

Ensure that your identifiers can be uniquely identified

If you don't include any way of uniquely identifying your identifiers, it's really hard for the diffable data source to find out what changed. For example, look at the following code:

let itemsBefore = [{ "name": "Donny Wals" }, { "name": "Donny Wals" }]
let itemsAfter = [{ "name": "Donny Wals" }, { "name": "Donny Wals" }]

The preceding snippet shows two arrays that appear to be identical. And while they might look identical, each object is its own entity. And they might have some kind of underlying ordering and the objects might have swapped positions. It's impossible to tell, right?

The same is true for your diffable data source. If you don't provide it anything unique to identify objects by, it can get confused easily which is probably not what you want. If you include some kind of known unique identifier like a UUID or an identifier that's used in your back-end, it's much easier to keep track of changes to ordering and individual changes. If you're reading data from a server that you won't modify and you know it already has a sense of uniqueness, for example if every item points to a unique resource on the web, it might be redundant to add an extra identifier yourself.

In summary

I hope I have been able to not only introduce you to diffable data sources, but I hope I have also been able to teach you how you can use them in the real world. Several blog posts I have seen were written shortly after WWDC 2019 and cover the very basics, and unfortunately Apple's documentation this year hasn't been fantastic. I'm sure they will get around to updating it eventually. Luckily, Apple did include some sample code in the links for their Advances in UI Data Sources talk from WWDC 2019.

In today's post, I have shown you how a diffable data source is defined, and how it's used. You saw that a diffable data source has two generic parameters; one for sections and one for items, and you saw that a diffable data source requires a snapshot of your models to render data. I have also explained how you can subclass UITableViewDiffableDataSource to add support for features like section headers and swipe-to-delete. Lastly, I shared some best practices that you should keep in mind when using diffable data sources.

If there's anything unclear after reading this post, or if you have feedback for me, make sure to reach out on Twitter. I love hearing from you.