Recent articles
Jump to a random postAdding your app’s content to Spotlight
Published on: March 23, 2020On iOS, you can swipe down on the home screen to access the powerful Spotlight search feature. Users can type queries in Spotlight and it will search through several areas of the system for results. You may have noticed that Spotlight includes iMessage conversations, emails, websites, and more. As an app developer, you can add content from your app to the Spotlight search index so your users can find results that exist in your app through Spotlight. An important aspect of the Spotlight index is that you can choose whether you want to index your app contents publicly, or privately....
Read more...Removing duplicate values from an array in Swift
Published on: March 18, 2020Arrays in Swift can hold on to all kinds of data. A common desire developers have when they use arrays, is to remove duplicate values from their arrays. Doing this is, unfortunately, not trivial. Objects that you store in an array are not guaranteed to be comparable. This means that it's not always possible to determine whether two objects are the same. For example, the following model is not comparable: struct Point { let x: Int let y: Int } However, a keen eye might notice that two instances of Point could easily be compared and two points that are...
Read more...Profiling and debugging your Combine code with Timelane
Published on: March 16, 2020When we write code, we write bugs. It's one of the laws of the universe that we can't seem to escape. The tools we have to discover, analyze and fix these bugs are extremely important because without good debugging tools we'd be poking at a black box until we kind of figure out what might be happening in our code. Debugging synchronous code is hard enough already, but once your code involves several streams of asynchronous work debugging becomes much harder because asynchronous code can be inherently hard to keep track of. Combine code is asynchronous by nature. When you...
Read more...What is @escaping in Swift?
Published on: March 11, 2020If you've ever written or used a function that accepts a closure as one of its arguments, it's likely that you've encountered the @escaping keyword. When a closure is marked as escaping in Swift, it means that the closure will outlive, or leave the scope that you've passed it to. Let's look at an example of a non-escaping closure: func doSomething(using closure: () -> Void) { closure() } The closure passed to doSomething(using:) is executed immediately within the doSomething(using:) function. Because the closure is executed immediately within the scope of doSomething(using:) we know that nothing that we do inside of...
Read more...What are computed properties in Swift and when should you use them?
Published on: March 9, 2020One of Swift's incredibly useful features is its ability to dynamically compute the value of a property through a computed property. While this is a super handy feature, it can also be a source of confusion for newcomers to the language. A computed property can look a bit strange if you haven't seen one before; especially when you are learning about custom get and set closures for properties at the same time. In this week's post, I would like to take some time to explain computed properties in-depth so you can begin using them in your codebase with confidence. By...
Read more...Reading and writing Property List files with Codable in Swift
Published on: March 4, 2020You have probably seen and used a property list file at some point in your iOS journey. I know you have because every iOS app has an Info.plist file. It's possible to create and store your own .plist files to hold on to certain data, like user preferences that you don't want to store in UserDefaults for any reason at all. In this week's Quick Tip you will learn how you can read and write data from and to property list files using Swift's Codable protocol. Defining a model that can be stored in a property list Because Swift has...
Read more...Using Result in Swift 5
Published on: March 2, 2020As soon as Swift was introduced, people were adding their own extensions and patterns to the language. One of the more common patterns was the usage of a Result object. This object took on a shape similar to Swift's Optional, and it was used to express a return type that could either be a success or a failure. It took some time, but in Swift 5.0 the core team finally decided that it was time to adopt this common pattern that was already used in many applications and to make it a part of the Swift standard library. By doing...
Read more...Using KeyPaths as functions in Swift 5.2
Published on: February 26, 2020One of Swift 5.2's new features is the ability to use KeyPaths as functions. This can be extremely useful in cases where you'd only return the value of a certain KeyPath in a closure. Let's look at a pre-Swift 5.2 example where this is the case: // Swift 5.1 and earlier struct User { let id: UUID let name: String let age: Int } func extractUserIds(from users: [User]) -> [UUID] { return users.map { $0.id } } This code should look familiar to you. It's likely that you've written or seen something like this before. This code transforms an array...
Read more...Using try catch in Swift
Published on: February 24, 2020In Swift 2.0, Apple introduced the throws keyword in Swift. This addition to Swift language added the ability for developers to write code that clearly communicates that an error might occur during the execution of a code path, and it forces the caller of that code to handle, or explicitly ignore the error in-place. In this post I will show you what the throws keyword is exactly, and how you can deal with errors in your codebase. Working with code that throws errors If you've worked with JSONDecoder in Swift, you have already experienced code that can throw an error....
Read more...Adding default values to subscript arguments in Swift 5.2
Published on: February 19, 2020The ability to define custom subscripts in Swift is really powerful. It allows us to write very natural and concise code. Consider the following example of a Grid with a custom subscript: struct Grid { let items : [[GridItem]] subscript(x x: Int, y y: Int) -> GridItem? { guard !items.isEmpty, (items.startIndex...items.index(before: items.endIndex)).contains(x) else { return nil } let row = items[x] guard !row.isEmpty, (row.startIndex...row.index(before: row.endIndex)).contains(y) else { return nil } return row[y] } } Note that subscripts don't use labels by default. To make a subscript use labels, you need to manually declare the subscript label twice like I did...
Read more...