Quick Tip
Calculating the difference in hours between two dates in Swift
Published on: March 25, 2020Sometimes you need to calculate the difference between two dates in a specific format. For instance, you might need to know the difference between dates in hours. Or maybe you want to find out how many days there are between two dates. One approach for this would be to determine the number of seconds between two dates using timeIntervalSince: let differenceInSeconds = lhs.timeIntervalSince(rhs) You could use this difference in seconds to convert to hours, minutes or any other unit you might need. But we can do better in Swift using DateComponents. Given two dates, you can get the difference in...
Read more...Removing duplicate values from an array in Swift
Published on: March 18, 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...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...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 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...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...Testing push notifications in the Simulator with Xcode 11.4
Published on: February 12, 2020For years we've had to resort to using physical devices when testing push notifications. With Xcode 11.4, Apple finally gives developers the tools needed to test push notifications on the iOS Simulator. I'm going to assume you already know how to add push notifications to your app. If you've never added push notifications to an app before, I have a post that describes how to set up and test push notifications without a third-party service. That post should get you all set up to follow along with this post. Sending a test push from the command line Xcode comes with...
Read more...Five ways to get better at receiving feedback
Published on: February 5, 2020When I just started my career as a developer there was a lot I didn't know yet. There also were a lot of things I didn't understand or had never done before. I have always been lucky enough to work in places where I was able to learn and grow as needed, and most importantly, I was allowed to make mistakes. One of the hardest things wasn't that I was constantly learning and figuring out. That actually was the fun part! The hard bit was often receiving feedback. Whether it was feedback from clients, coworkers or teachers back in college....
Read more...Updating UI with assign(to:on:) in Combine
Published on: January 29, 2020So far in my series of posts about Combine, we have focussed on processing values and publishing them. In all of these posts, I used the sink method to subscribe to publishers and to handle their results. Today I would like to show you a different kind of built-in subscriber; assign(to:on:). This subscriber is perfect for subscribing to publishers and updating your UI in response to new values. In this post, I will show you how to use this subscriber, and I will show you how to avoid memory issues when using assign(to:on:). Using assign(to:on:) in your code If you've...
Read more...Debugging network traffic with Charles
Published on: January 22, 2020When you perform a URL Request in your app, you typically configure the request in your code and when it's all set up you pass it off to a URLSession data task, and the request should succeed if everything goes as expected. When the request is misconfigured, the server will hopefully return a useful error and you can fix your code accordingly. There are times, however, where the server does not give the information you need. Or your requests succeed but your results are not quite what you expect. It's times like these when I really wish that there was...
Read more...