What is Module Stability in Swift and why should you care?

The Swift team has recently released Swift 5.1. This version of the Swift language contains many cool features like Function Builders that are used for SwiftUI and Property Wrappers that can be used to add extra functionality to properties. This release also contains a feature called Module Stability. But what is this feature? And what does it mean to you as a developer? In this week’s blog post, I will explain this to you. But before we get to Module Stability, let’s do a little time traveling back to Swift 5.0, which shipped with ABI (Application Binary Interface) Stability.

Understanding ABI Stability

Up to Swift 5.0, every time you built an app with Swift, your app would include the entire Swift standard library and runtime. The reason for this was that Swift was changing so much that it wasn’t feasible to include the Swift fundamentals into releases of iOS. Swift 5.0 changed this with ABI Stability. Swift now defines a stable binary interface that will not change across Swift versions. In practice, this means that the Swift 5.1 (or later) runtime can execute code that was compiled with the Swift 5.0 compiler due to this stable interface definition.

When you write code, you do not need to understand or think about this binary interface, or ABI. This is all handled internally by the Swift compiler and it’s possible that the biggest win for your app is simply that your application binary is smaller for iOS versions that include the Swift runtime because the App Store will now strip the Swift runtime out of your binary if your app is being downloaded on a platform that has ABI Stability.

One common misunderstanding I’ve seen with ABI stability is that people were hoping that it would allow them to use frameworks that are compiled with Swift 5.0 in a project that uses the Swift 5.1 compiler. Unfortunately, this is not the case and the following error is likely one that you’ve encountered when you upgraded from Swift 5.0.1 to Swift 5.1.

Module compiled with Swift 5.0.1 cannot be imported by the Swift 5.1 compiler

This brings us to the Module Stability introduced by Swift 5.1.

Understanding Module Stability

While Module Stability and ABI stability are completely different animals altogether, they are also quite similar. While ABI Stability allows programs written with different versions of Swift to exist in a shared runtime, Module Stability allows you to use frameworks compiled with different versions of swift in a project that might use yet another version of Swift. The way this works is best explained by the following excerpt from the Swift 5.1 release announcement:

Swift 5.1 enables the creation of binary frameworks that can be shared with others leveraging the language’s added support for module stability. Module stability defines a new text-based module interface file that describes the API of a binary framework, allowing it to be compiled with code using different versions of the compiler.

Binary frameworks that were built with Module Stability enabled contain a special folder with the .swiftmodule suffix which contains .swiftinterface and .swiftmodule files. These files are the text-based definition of your framework's API that is mentioned in the Swift 5.1 release announcements. To build your own frameworks with support for module stability you need to enable the Build Library for Distribution setting in your framework's Project Settings pane and set the Skip Install property to NO. After doing this, Xcode includes the .swiftmodule in your product when you archive it, making your framework "module stable".

Every binary framework that is compiled with the Swift 5.1 compiler and Xcode 11 or later can be used in any project that uses Swift 5.1 or later as long as the Build Library for Distribution and Skip Install properties are configured correctly. So, in short, Module Stability means that you should never see an error message that reads “Module compiled with Swift 5.1 cannot be imported by the Swift 5.2 compiler” because all frameworks that were built with module stability are automatically compatible with the Swift version it was built for and newer. Pretty cool, right?

In conclusion

Now that we have Module Stability and ABI Stability in Swift, the language is likely to change at a slower rate than we’re used to. We should see less radical, source breaking changes and the language should slowly mature into a beautiful, fast and stable language that will be a great basis for your applications for years to come. However, don’t think that Swift will stop innovating and evolving. The Swift Evolution forum is still going strong and folks are still working very hard to make Swift a versatile, safe and clean language to work with.

As always, feedback, compliments, and questions are welcome. You can find me on Twitter if you want to reach out to me.

Finding the difference between two Arrays

Many applications work with data, often they are built to retrieve data and display this data to the user in a table view, collection view, list (if you're using SwiftUI) or a different kind of component. It's not uncommon for this data to change and when it does you might be interested in figuring out what elements were added to the data and which items were removed. This isn't always straightforward so up until now you might have written code something like the following:

func didFetchNewRecipes(_ newRecipes: [Recipe]) {
  recipes = newRecipes
  tableView.reloadData()
}

Simple and effective, much easier than figuring out the difference and only reloading the cells that have changed. On iOS 13, you can use new methods on any collection that conforms to BiDirectionalCollection to determine the changes between two collections as long as the items that are contained in the collection conform to Equatable. You can then use the information from this method to update a table view:

func didFetchNewRecipes(_ newRecipes: [Recipe]) {
  let changes = newRecipes.difference(from: recipes)

  let insertedIndexPaths = changes.insertions.compactMap { change -> IndexPath? in
    guard case let .insert(offset, _, _) = change
      else { return nil }

    return IndexPath(row: offset, section: 0)
  }

  let removedIndexPaths = changes.removals.compactMap { change -> IndexPath? in
    guard case let .remove(offset, _, _) = change
      else { return nil }

    return IndexPath(row: offset, section: 0)
  }

  self.recipes = newRecipes
  tableView.beginUpdates()
  tableView.insertRows(at: insertedIndexPaths, with: .automatic)
  tableView.deleteRows(at: removedIndexPaths, with: .automatic)
  tableView.endUpdates()
}

Tip:
If your elements are not Equatable, use the differences(from:by:) method to supply a closure where you can perform your own comparison to determine if two elements are equal.

Cool stuff right? What kind of applications do you see for this kind of method? Let me know on Twitter!

Getting started with unit testing your Swift code on iOS – part 2

In part 1 of this two-part blog post, you’ve learned how to write synchronous unit tests for a login view model. As a reminder, you saw how to implement tests for the following requirements:

  • When both login fields are empty, pressing the login button should trigger an error that informs the user that both fields are mandatory.
  • When one of the two fields is empty, pressing the login button should trigger an error that informs the user that the empty field is mandatory.
  • When the user’s email address does not contain an @ symbol, pressing the login button should trigger an error that informs the user that they must provide a valid email address.

You implemented these requirements using a LoginFormViewModel that has two properties for the username and password and a login method. And of course, you wrote tests for every requirement listed. If you want to start following this blog post with the final code of the previous part, check out the HelloUnitTest-PartOne folder in this blog post’s GitHub repository.

In this second part, you will learn how to refactor the current test suite to support asynchronous code. You will also implement a networking abstraction that will act as a fake server for login requests.

The objective of this blog post

Just like in the previous post, you will implement tests for a couple of requirements. This time, there are just two requirements:

  • When the user’s credentials are filled in, but the server doesn’t recognize the email address or the password is wrong, an error should be triggered that informs the user that their credentials were incorrect.
  • When the user’s credentials are filled in and they are valid, the login method should invoke the completion handler with a User object.

So, without further ado, let’s dive right in and begin refactoring and writing some more test code!

Getting to work

The first requirement we’re going to implement is the following:

  • When the user’s credentials are filled in, but the server doesn’t recognize the email address or the password is wrong, an error should be triggered that informs the user that their credentials were incorrect.

Note that this requirement speaks of a server. In this post, I will not focus on the nitty-gritty details and many possibilities of setting up a mock networking layer. Instead, I will show you a basic form of abstracting a network layer so you can do testing with it. First, let’s refactor the existing code from part 1 so it’s ready for the new asynchronous nature of the tests you’re going to write in this post.

In order to make the form view model asynchronous, we’re going to change the code first and update the existing tests after. I will assume that your code looks identical to the code that’s in the HelloUnitTests-PartOne folder of this blog post’s GitHub repository. The login method on the LoginFormViewModel should be changed so it supports asynchronous execution. This means that the method should no longer throw errors and instead invoke a completion handler with a result of type Result<User, Error>. You will define user as an empty struct since we’re not going to actually decode and create User objects later. The definition of User should look as follows:

struct User {

}

Completely empty. Simple right? You can either put it in its own file or throw it in the LoginFormViewModel.swift file since it’s just an empty struct. Next, rewrite the login method as follows:

func login(_ completion: @escaping (Result<User, LoginError>) -> Void) {
  guard let password = password, let username = username else {
    if self.username == nil && self.password == nil {
      completion(Result.failure(LoginError.formIsEmpty))
    } else if self.username == nil {
      completion(Result.failure(LoginError.usernameIsEmpty))
    } else {
      completion(Result.failure(LoginError.passwordIsEmpty))
    }
    return
  }

  guard username.contains("@") else {
    completion(Result.failure(LoginError.emailIsInvalid))
    return
  }
}

If at this point you’re thinking: “Hey! This isn’t right. TDD dictates that we change our tests first”, you would be absolutely right. However, I find that sometimes it’s simpler to have a bunch of passing tests, then refactor your logic, and refactor the tests to match afterwards. It’s really a preference of mine and I wanted to make sure you see this method of writing code and tests too.

Let’s refactor the tests so they compile and pass again. I will only show you how to refactor a single test case, all the other test cases should be refactored in a similar way. Again, if you get stuck, refer to this blogpost’s GitHub repository. The solutions for this part of the post are in the HelloUnitTests-PartTwo folder. Refactor the testEmptyLoginFormThrowsError method in your test file as follows:

func testEmptyLoginFormThrowsError() {
  XCTAssertNil(loginFormViewModel.username)
  XCTAssertNil(loginFormViewModel.password)

  // 1
  let testExpectation = expectation(description: "Expected login completion handler to be called")

  loginFormViewModel.login { result in
    guard case let .failure(error) = result, case error = LoginError.formIsEmpty else {
      XCTFail("Expected completion to be called with formIsEmpty")
      testExpectation.fulfill()
      return
    }

    // 3
    testExpectation.fulfill()
  }

  // 2
  waitForExpectations(timeout: 1, handler: nil)
}

This test contains a couple of statements that you haven’t seen before. I have added comments with numbers in the code so we can go over them one by one.

  1. This line of code creates a so-called test expectation. An expectation is an object that is used often when testing asynchronous code. Expectations start out in an unfulfilled state and remain like that until you call fulfill on them. If you never call fulfill, your test will eventually be considered failed.
  2. At the end of the test method, waitForExpectation is called. This method instructs the test that even though the end of the control flow has been reached, the test is not done executing yet. In this case, the test will wait for one second to see if all expectations are eventually fulfilled. If after one second there are one or more unfulfilled expectations in this test, the test is considered to be failed.
  3. Since the login method is now asynchronous, it received a callback closure that uses Swift’s Result type. Once the result has been unpacked and we find the error that we expect, the expectation that was created earlier is fulfilled. If the expected error is not found, the test is marked as failed and the expectation is also fulfilled because the completion handler was called. There is no need to wait a full second for this test to fail since the XCTFail invocation already marks the test as failed.

Now that login supports callbacks, we can write a new test that makes sure that the LoginFormViewModel handles server errors as expected. To do this, we’re going to introduce a dependency for LoginFormViewModel. Using a specialized object for the networking in an application allows you to create a mock or fake version of the object in your test, which provides a high level of control of what data the fake network object responds with.

This time, we’re going to jump from implementation code into tests and then back into implementation code. First, add the following protocol definition to LoginFormViewModel.swift:

protocol LoginService {
  func login(_ completion: @escaping (Result<User, LoginError>) -> Void)
}

This protocol is fairly straightforward. It dictates that any networking object acting as a login service must have a login method that takes a completion handler that takes a Result<User, LoginError> object. This method signature is identical to the one you’ve already seen on the LoginFormViewModel. Next, add a property to the LoginFormViewModel to hold the new login service:

let loginService: LoginService

Finally, call the login method on the login service at the end of LoginFormViewModel’s login method:

func login(_ completion: @escaping (Result<User, LoginError>) -> Void) {
  // existing code

  guard username.contains("@") else {
    completion(Result.failure(LoginError.emailIsInvalid))
    return
  }

  loginService.login(completion)
}

So far so good, now let’s make the tests compile again. Add a property for the login service to your test class and update the setUp method as shown below:

var loginService: MockLoginService!

override func setUp() {
  loginService = MockLoginService()
  loginFormViewModel = LoginFormViewModel(loginService: loginService)
}

Note that this code uses a type that you haven’t defined yet; MockLoginService. Let’s implement that type now. Select your test suite’s folder in Xcode’s File Navigator and create a new Swift file. When naming the file, double check that the file will be added to your test target and not to your application target. Name it MockLoginService and press enter. Next, add the following implementation code to this file:

import Foundation
@testable import HelloUnitTests

class MockLoginService: LoginService {
  var result: Result<User, LoginError>?

  func login(_ completion: @escaping (Result<User, LoginError>) -> Void) {
    if let result = result {
      completion(result)
    }
  }
}

The code for this file is pretty simple. The mock login service has an optional result property that we’re going to give a value later in the test. The login method that will be called from the login view model immediately calls the completion block with the result that is defined by the test. This setup is a cool way to fake very basic network responses because your application code can now use any object that conforms to LoginService. You create and inject a real networking object if you’re starting your app normally, and you create and inject a mock networking object when you’re running tests. Neat!

Note that the MockLoginService is a class and not a struct. Making this object a class ensures that any assignments to result are applied to all objects that have a reference to the MockLoginService. If you’d make this object a struct, every object that receives a MockLoginService will make a copy and assignments to result would not carry over to other places where it’s used.

Your tests should still run and pass at this point. We are now ready to finally add that test we set out to write in the first place:

func testServerRespondsWithUnkownCredentials() {
  loginFormViewModel.username = "[email protected]"
  loginFormViewModel.password = "password"
  XCTAssertNotNil(loginFormViewModel.username)
  XCTAssertNotNil(loginFormViewModel.password)

  loginService.result = .failure(LoginError.incorrectCredentials)

  let testExpectation = expectation(description: "Expected login completion handler to be called")

  loginFormViewModel.login { result in
    guard case let .failure(error) = result, case error = LoginError.incorrectCredentials else {
      XCTFail("Expected completion to be called with incorrectCredentials")
      testExpectation.fulfill()
      return
    }

    testExpectation.fulfill()
  }

  waitForExpectations(timeout: 1, handler: nil)
}

The above code looks very similar to the asynchronous test code you’ve already written. The major difference here is on line 7: loginService.result = .failure(LoginError.incorrectCredentials). This line of code assigns a failure response with a specific error to the mock login service’s result property. All other code is pretty much unchanged when you compare it to your previous tests. Now add the incorrectCredentials error case to your LoginError enum and run the tests. They should pass, which indicates that the LoginFormViewModel uses a networking object and that it forwards errors that it received from the networking object to the calling object.

You now have enough information to implement the final test case yourself:

  • When the user’s credentials are filled in and they are valid, the login method should invoke the completion handler with a User object.

When you’re done and want to check your solution, or if you’re stuck, don’t hesitate to check out the GitHub repository for this post.

Next steps

First of all, congratulations on making it this far! You’ve achieved a lot by working through all of the examples shown in this two-part post. Part one showed you how to write simple unit tests, and with the information from this second part, you can even write tests for asynchronous code. Moreover, you now even have an idea of how you can architect your application code to be easily testable by using protocols as an abstraction layer.

Of course, there is much more to learn about testing. For now, you should have plenty of information to stay busy, but if you’re eager to start learning more, I can recommend taking a look at some other blog posts I wrote about testing:

Alternatively, you can try to refactor the test suite a little bit by removing some of the code duplication you’ll currently find in there. After all, test code is code too, and we should aim to make it as DRY and high-quality as possible.

Getting started with unit testing your Swift code on iOS – part 1

Recently, I ran a poll on Twitter and discovered that a lot of people are not sure how to get started writing tests, or they struggle to get time approved to write tests for their code. In this blogpost, I will take you through some of the first steps you can take to start writing tests of your own and help you pave the way to a more stable codebase.

Why bother with tests at all?

You might be wondering why you should bother with code that tests your code. When you put it like that, the idea might indeed sound silly. To others, tests sound so horribly complex that writing them can hardly be easier and more stable than just writing code and testing your app by hand.

These are valid thoughts, but think of the last time you had to test something like a preferences form where you needed to make sure that every input you throw at it produces the expected output. Especially if the form contains something like email validation, testing the form can be time-consuming because there are so many valid and invalid inputs. After executing a couple of manual tests, you’re probably confident that everything works as expected and you stop testing it altogether until a user finds a bug in your logic.

What if I told you that an automated test can do the exact thing that takes you several minutes to check in less than a second. That’s pretty amazing, right? Once a test is written, it is a part of your test suite forever. This means that any time you run the test suite, you’re not only testing the feature you’re working on; you’re testing every feature you’ve ever written. All in the time it takes you to grab a cup of coffee.

The confidence that you can gain from having a test suite is liberating. And the fact that you simply know that nothing broke and everything works pretty much exactly as planned (we all forget test cases from time to time), ensures that every time you commit your code, you do so with confidence.

The objective of this blog post

In this two-part blog post, you’re going to build a very simple login form. You won’t actually build the form itself, because all logic for the form will be encapsulated in a ViewModel that you will write tests for. Don’t worry if you don’t know MVVM, never used it, or simply don’t like it. The point of this post isn’t to convince you that MVVM is the one architecture to rule them all (it isn’t) but simply to have a somewhat real-world scenario to write tests for.

By the end of this post, you should have some understanding of how you can structure your code and tests. You should also be able to adapt this to virtually any other code base that you come across. Before we get to writing the tests, let’s define a couple of basic acceptance criteria that we’re going to write tests for in this post.

  • When both login fields are empty, pressing the login button should trigger an error that informs the user that both fields are mandatory.
  • When one of the two fields is empty, pressing the login button should trigger an error that informs the user that the empty field is mandatory.
  • When the user’s email address does not contain an @ symbol, pressing the login button should trigger an error that informs the user that they must provide a valid email address.

The requirements above are somewhat incomplete, but they should reflect a sensible set of tests that you might want to write for a login form. If you want to follow along with all code written in this post and the next, now is the time to launch Xcode and create a new project. Make sure you check the “Include Unit Tests” checkbox when creating the project. Since SwiftUI is still brand new and not everybody is able to use it in their projects, we’ll use a Storyboard based template for now. If you accidentally chose SwiftUI, that’s okay too, we’re not building UI in this post.

Writing your first test

If you’ve created your project with the “Include Unit Tests” checkbox enabled, you’ll find a folder that had the Tests suffix in the Project Navigator. This folder belongs to your test suite and it’s where you should add all your unit test files. The default file contains a couple of methods that are important to understand. Also note that there is a special import declaration near the top of the file. It has the @testable prefix and imports your app target. By importing your app or framework with the @testable prefix, you have access to all public and internal code that’s in your app or framework.

The setUp and tearDown methods

If your test code contains shared setup logic, you can use the setUp method to perform work that must be performed for every test. In our tests, we’ll use the setUp method to create an instance of the LoginFormViewModel. Similar to the setUp method, the tearDown method can be used to release or reset certain resources that you may have created for one test, but don’t want sticking around for the next test.

The test methods

In addition to setUp and tearDown, the default template Xcode provides contains two methods that have the test prefix. These test methods are your actual tests. Any method in an XCTectCase subclass with the test prefix is considered a test by XCTest and will be executed as part of your test suite.

The testPerformanceExample shows a very basic setup for performance testing. This is useful if you want to make sure that a complex algorithm you’re working on doesn’t become much slower in future iterations of your work. We’ll ignore that method for now, since we won’t be doing any performance testing in this post. Go ahead and remove testPerformanceExample from the file.

Now that you have an idea of what a test file contains, let’s rename the testExample to testEmptyLoginFormThrowsError and learn how to implement your first test!

Getting to work

Since you already have the test file open, let’s write a test for the login form first. After that, we can start implementing the form. First, add a property for the login form to the test class:

var loginFormViewModel: LoginFormViewModel!

As mentioned before, the setUp method should be used to create a new instance of the login form view model for every test case. Add the following implementation for setUp to create the view model:

override func setUp() {
  loginFormViewModel = LoginFormViewModel()
}

Your code doesn’t compile at this point. This is expected since the LoginFormViewModel is not defined yet. Writing tests before you write an implementation is common practice in Test Driven Development. You’ll create an implementation for LoginFormViewModel right after implementing your first test.

Every test we write will now have access to a fresh instance of LoginFormViewModel. The first test we’re going to write makes sure that when both the username and the password on the login form are empty and that we receive a specific error whenever we attempt to login. XCTest uses assertions to ensure that certain values are exactly what they should be. To check if something is nil for example, you use the XCTAssertNil method. Add the following two lines of code to testEmptyLoginFormThrowsError to assert that both username and password are nil:

XCTAssertNil(loginFormViewModel.username)
XCTAssertNil(loginFormViewModel.password)

If either the username or password property is true, XCTest will mark that assertion and the test itself as failed. XCTAssertNil is a fairly simple assertion. Let’s look at a somewhat more complex assertion to check whether login in throws an appropriate error:

XCTAssertThrowsError(try loginFormViewModel.login()) { error in
  guard case let LoginError.formIsEmpty = error else {
    XCTFail("Expected the thrown error to be formIsEmpty")
  }
}

The code above asserts that loginFormViewModel.login() throws an error. The XCTAssertThrowsError method accepts a closure that can be used to inspect the error that was thrown. In this case, we want to make sure that the thrown error is the expected error. If we receive the wrong error, we fail the test by calling XCTFail with a failure message. If your test fails due to login throwing an unexpected error, Xcode will show the message you provided to XCTFail in the console to provide some guidance in figuring out exactly why your test failed.

Now that you have an entire test prepared, let’s write the code that needs to be tested! Select your app’s folder in the file navigator and create a new Swift file called LoginFormViewModel. Define a new LoginFormViewModel struct and give it a username and password property that are both defined as var and of type String?. Also, define a login method and mark it as throwing by adding throws after the method signature.

Since your test expects a specific error to be thrown, define a new enum outside of the LoginFormViewModel and name it LoginError. Make sure it conforms to Error and add a single case to the enum called formIsEmpty. After creating the enum, add the following line of code to your login() method:

throw LoginError.formIsEmpty

This might seem strange to you. After all, shouldn’t login() only throw this error if both the username and password are nil? And you’d be absolutely correct. However, since we’re writing the test suite using an approach that is loosely based on Test Driven Development, we should only be writing code to make tests pass. And since we’ve only written a single test, the current implementation is correct based on the test suite. By working like this, you can be sure that you’re always testing all the code paths you want to test. Later in this blog post, you’ll refactor the login() method to do nil checking and more.

At this point, you should have the following contents in your LoginFormViewModel.swift file:

import Foundation

enum LoginError: Error {
  case formIsEmpty
}

struct LoginFormViewModel {
  var username: String?
  var password: String?

  func login() throws {
    throw LoginError.formIsEmpty
  }
}

Go back to your test file and run your tests by pressing cmd + u. Your project and test suite should build, and after a couple of seconds, you should get a notification saying that your tests passed. Note the green checkmarks next to your test class and the testEmptyLoginFormThrowsError method.

Congratulations! You have written your first test. Now let’s switch into second gear and walk through the process of expanding the tests for your view model.

Completing the objective

You have currently implemented one out of three tests that are needed for us to consider the objective to be complete. Both of the remaining tests are very similar to the test you wrote earlier.

  • When one of the two fields is empty, pressing the login button should trigger an error that informs the user that the empty field is mandatory.
  • When the user’s email address does not contain an @ symbol, pressing the login button should trigger an error that informs the user that they must provide a valid email address.

Try to implement these on your own. If you get stuck you can either look back at the test you already wrote or have a look at the GitHub repository that contains the completed test suite and implementation for this blog post. The solution for requirements one through three are in the folder HelloUnitTests-PartOne.

Hint: one of the requirements is best tested with two separate test cases and you should use an assertion method that confirms something is not nil.

If you’ve managed to implement both tests without looking at the solution on GitHub, I tip my hat to you, well done! If you did have to sneak a peek, don’t worry. You completed the assignment and you have learned a couple of things about writing tests!

Concluding part 1

In this first part of Getting started with unit testing on iOS you have learned how to write some basic, synchronous tests. Try coming up with some more tests you can execute on the view model, or maybe attempt to create a registration view model that has a couple of more fields and validation rules.

In the next part of this blog post, you will apply some major refactors to the test suite you’ve built in this post to do some asynchronous testing. You’ll also learn how to create a testable abstraction for networking logic! Grab some coffee, take a breath and click right through to Getting started with unit testing on iOS - part 2.

Supporting Low Data Mode in your app

Together with iOS 13, Apple announced a new feature called Low Data Mode. This feature allows users to limit the amount of data that’s used by apps on their phone. The low data mode setting is available in the settings app. Whenever a user is on a slow network, a very busy network or on a network that might charge them for every megabyte they download, users might not want to spend their limited data budget on large fancy images or clever prefetching logic. With Low Data Mode, users can now inform your app that they are on such a network so you can accommodate their needs accordingly.

It’s up to app developers to support low data mode and handle the user’s preferences with care. In their 2019 WWDC talk Advanced In Networking Part One, Apple suggests to at least adopt low data mode for features that will have limited to no impact on the user experience. A good example of this might be to limit the amount of data prefetching and syncing your app does to prevent making requests of which the result will never be visible to the user.

One clever integration example of low data mode that Apple gives in their talk is graceful degradation of images. Any time your app wants to load an image, it should fall back to a smaller, lower-quality version if low data mode is enabled. In this post, I will show you how you can implement a feature like this, and what other ways there are for you to integrate low data mode in your apps.

A simple fallback integration

In its most basic form, you can configure low data mode support separately for each request your app makes. The following code shows how you can create a request that will honor a user’s low data mode preferences:

guard let url = URL(string: "https://someresource.com")
  else { return }

var request = URLRequest(url: url)
request.allowsConstrainedNetworkAccess = false

By setting allowsConstrainedNetworkAccess to false on the URLRequest, you’ve done all the work needed to support low data mode. When you attempt to execute this URLRequest while Low Data Mode is active, it will fail with a URLError that has its networkUnavailableReason property set to .constrained. So whenever your request fails with that error, you might want to request a resource that consumes less data if needed, like a lower quality image. The following code snippet shows how to do this using the request from the previous snippet:

URLSession.shared.dataTask(with: request) { data, response, error in
  if let error = error {
    if let networkError = error as? URLError, networkError.networkUnavailableReason == .constrained {
      // make a new request for a smaller image
    }

    // The request failed for some other reason
    return
  }

  if let data = data, let image = UIImage(data: data) {
    // image loaded succesfully
    return
  }

  // error: couldn't convert the data to an image
}

I have omitted the error handling and the URLRequest for the smaller image because these features might be specific for your app and implementing them shouldn’t be too daunting.

In case you’re wondering how you can do this using Apple’s new Combine framework, I’ll gladly show you. The following snippet is a complete example of a method that accepts a high quality and low-quality image URL, attempts to load to high-quality one but falls back on the low-quality version if low data mode is enabled:

func fetchImage(largeUrl: URL, smallUrl: URL) -> AnyPublisher<UIImage, Error> {
  var request = URLRequest(url: largeUrl)
  request.allowsConstrainedNetworkAccess = false

  return URLSession.shared.dataTaskPublisher(for: request)
    .tryCatch { error -> URLSession.DataTaskPublisher in
      guard error.networkUnavailableReason == .constrained else {
        throw error
      }

      return URLSession.shared.dataTaskPublisher(for: smallUrl)
  }.tryMap { (data, _) -> UIImage in
    guard let image = UIImage(data: data) else {
      throw NetworkError.invalidData
    }

    return image
    }.eraseToAnyPublisher()
}

The above snippet uses the dataTaskPublisher(for:) method to create a DataTaskPublisher. If this publisher emits an error, the error is caught to see if the error was thrown due to Low Data Mode being enabled. If this is the case, a new DataTaskPublisher is created. This time for the low-quality URL. If the request succeeds, the retrieved data is converted to an image in a tryMap block. If the conversion fails an error is thrown. Note that NetworkError.invalidData is not a built-in error, it’s one that you’d have to define yourself. Lastly, the result of tryMap is converted to an AnyPublisher to make it easier to work with for callers of fetchImage(largeUrl:, smallUrl:).

And that’s it! A complete implementation of low data mode with a fallback in less than 20 lines of code.

Enabling low data mode for an entire URLSession

If you find that supporting low data mode on a case by case basis for your requests is tedious, you can also set up an entire URLSession that restricts network access when low data mode is enabled. I won’t show you how to make requests and implement fallback logic since this is all done identically to the previous example. The only difference is that you should use your own URLSession instance instead of the URLSession.shared instance when you create data tasks. Here’s an example of a URLSession with a configuration that supports low data mode:

var configuration = URLSessionConfiguration.default
configuration.allowsConstrainedNetworkAccess = false
let session = URLSession(configuration: configuration)

With just three lines of code, all of your URL requests (that are made using the custom session) support low data mode! No extra work needed. Pretty rad, right? But what if you want to restrict something else, like for example media playback? No worries, that also works. Let me show you how.

Low data mode for media playback

Media playback is possibly one of the best ways to use heaps of a user’s data in your app. Some apps use video assets as beautiful backgrounds or rely on video for other non-essential tasks. If this sounds like your app, you might want to implement low data mode for media playback. If you’re using AVURLAsset in your app, implementing low data mode is fairly straightforward. All you need to do is set the AVURLAssetAllowsConstrainedNetworkAccessKey on the asset’s options dictionary to false and AVPlayer takes care of the rest. A small snippet for reference:

guard let mediaUrl = URL(string: "https://yourdomain.com/media.mp4")
  else { return }

let asset = AVURLAsset(url: mediaUrl, options: [AVURLAssetAllowsConstrainedNetworkAccessKey: false])

Straightforward and effective, I like it.

Detecting Low Data mode without relying on an error

If you want to be pro-active with your low data mode implementation, and for instance warn a user that they are about to engage in an activity that will potentially use more data than they would like, you can use the Network framework. Apple's Network framework is typically used if you want to perform very low-level networking management that you can't achieve with URLSession. Since URLSession doesn't appear to have any way to detect whether a user has low data mode turned on before making a request, you must fall back to Network to do this kind of detection. The following code is an example of how you can detect that a user has low data mode turned on using the Network framework:

let monitor = NWPathMonitor()

monitor.pathUpdateHandler = { path in
  let constrained = path.isConstrained
}

monitor.start(queue: DispatchQueue.global())

The code above uses an NWPathMonitor to monitor the available networking paths on the device. When a path becomes available or if a path changes, the monitor will call its pathUpdateHandler with the available, recently changed path. The monitor won't work until you call its start method. Depending on your needs, coding styles and conventions you might want to create a dedicated dispatch queue that the monitor will call the update handler on. Also note that you'll want to keep a reference to the NWPathMonitor in the object that is using the monitor to prevent it from being deallocated before its update handler is called.

Thanks to @codeOfRobin for pointing out that NWPath can help with detecting low data mode.

Other considerations to limit unwanted data usage

In addition to giving you the ability to support low data mode, Apple has introduced another way for your app to prevent overuse of data. If you want to limit data usage on cellular networks, mobile hotspots and potentially on other expensive networks, you can use the allowsExpensiveNetworkAccess setting on URLSession and URLRequest or the AVURLAssetAllowsExpensiveNetworkAccessKey key on AVURLAsset to limit expensive data usage. NWPath also has an isExpensive property to detect whether a user is using an expensive network. If you’re currently restricting cellular access, you might want to consider checking for expensive networks instead. After all, cellular networks are improving all the time and maybe someday in the future they might not always be considered expensive anymore.

In conclusion

This post has shown you several ways to support low data mode in your app:

  1. By configuring your URLRequest
  2. By applying a configuration to a URLSession
  3. By configuring your AVURLAsset for low data mode

You also learned how to implement an image loader that falls back to a lower quality image using Combine, which is pretty cool on its own!

It is now up to you to come up with clever fallbacks, and to take a good look at the data you send and receive over the network, and ask yourself whether you truly need to make every request, or maybe you can optimize things a little bit.

As always, feedback, compliments, and questions are welcome. You can find me on Twitter if you want to reach out to me.

Also, thanks to @drarok for helping me make the Swift compiler happy with the Combine part of this post!

Spend less time maintaining your test suite by using the Builder Pattern

Often when we write code, we have to initialize objects. Sometimes the object’s initializer doesn’t take any arguments and a simple let object = MyObject() call suffices to create your object, other times things aren’t so simple and you need to supply multiple arguments to an object’s initializer. If you have read my previous post, Cleaning up your dependencies with protocols , you might have refactored your code to use protocol composition to wrap dependencies up into a single object that only exposes what’s needed to the caller. In this blogpost I would like to show you a technique I use when this kind of composition isn’t an option.

What problem are we solving exactly?

Before I dive in and show you how you can use builders in your test suite, let’s take some time to fully appreciate the problem we’re trying to solve. Imagine you’re building a very simple logger object that has the following initializer:

init(sink: LogSink) {
  self.sink = sink
}

All you need to do to create a logger, is provide it with a log sink and you’re good to go. In your test you might have written several tests for your logger, for instance:

func testLoggerWritesToSuppliedSink() {
  let sink = MockLogSink()
  let logger = Logger(sink: sink)
  logger.log("hello world")
  XCTAssertTrue(sink.contains("hello world")
}

In most applications, you’ll create a single instance of a logger in your AppDelegate, some kind of root coordinator, view model or other top-level object that is responsible for bootstrapping your application. However, in your test suite, you should be creating a new instance of your logger every time you want to test this. You do this to avoid tests accidentally influencing each other. Every test should start with a clean slate.

I want you to keep this in mind and think of the impact that changing the logger’s initializer would have. For instance, what’s the impact of changing the logger’s initializer to the following:

init(sink: LogSink, config: LogConfig) {
  self.sink = sink
  self.config = config
}

Obviously, you’re going to have to update the initializer you’re using in your application code. But you might also have to update dozens of other calls to the Logger initializer in your test suite. You might even have to update several tests that are unrelated to the logger itself, where the logger is used as a dependency for another object.

Personally, when I make changes to my code, I want the impact of that to be minimal. Finding out that there might be dozens of lines of code that I have to update when I change an initializer is not something I enjoy, especially if I can avoid it. This is the exact reason why I’d like to show you the Builder Pattern as it’s a fantastic way to minimize the impact of this kind of problem.

Introducing: the Builder Pattern

If you’ve studied design patterns, the Builder Pattern should be familiar to you. The very short explanation of this pattern is that you use an intermediate object (the builder) to create instances of an object for you so you don’t have to concern yourself with the details of object creation. Besides the use case I will show you in a moment, a builder can have several other benefits, for instance, you could use it to create different versions of an object depending on whether your app is built in debug or release mode.

In the context of testing, I really like to use the builder pattern for two reasons:
1. I don’t have to change a lot of code every time I refactor.
2. Test code is cleaner because it’s not polluted with information about creating an object if it’s not relevant to my test.

Before I explain the pattern and it’s usage a little bit more, let’s have a look at an example builder and how it would be used in context.

// The builder
class LoggerBuilder {
  var sink: LogSink = MockLogSink()
  var config: LogConfig = TestLogConfig()

  func build() -> Logger {
    return Logger(sink: sink, config: config)
  }
}

// in a test class
func testLoggerWritesToSuppliedSink() {
  let loggerBuilder = LoggerBuilder()
  let logger = loggerBuilder.build()
  logger.log("hello world")
  XCTAssertTrue(loggerBuilder.sink.contains("hello world")
}

The code above is a good example of how the builder pattern can hide some of the complexities that you’re unlikely to be interested in while writing your tests. For example, it’s likely that all of your tests will use the exact same configuration object, and it’s very possible that the MockLogSink contains all the functionality you need to use and test your logger in most of your test cases.

To make effective use of this pattern in your tests, there are a couple of rules to keep in mind. First, the builder should always be a reference type with mutable properties. This allows users of the builder to override certain properties on the object that is created. In the case of the logger, you’ll likely want to write a couple of tests that verify that a logger handles certain configurations as expected. You can achieve this by setting the config property on the builder:

let loggerBuilder = LoggerBuilder()
loggerBuilder.config = SpecialConfig()
let logger = loggerBuilder.build()

This brings me to the second rule. A builder must always construct and return a new instance when build() is called. This will make sure that any customizations that are performed by the user of your builder are actually applied.

The third rule of the builder pattern as I use it is that it should do as little work as possible in the build() method. And it’s strictly forbidden to create instances of objects that would be passed to the built object. For example:

// Don't do this!
class ProfileViewModelBuilder {
  var userProfile: UserProfile = MockUserProfile()

  func build() -> ProfileViewModel {
    let logger = LoggerBuilder().build()
    return ProfileViewModel(userProfile: userProfile, logger: logger)
  }
}

// Do this instead
class ProfileViewModelBuilder {
  var userProfile: UserProfile = MockUserProfile()
  var logger = LoggerBuilder().build()

  func build() -> ProfileViewModel {
    return ProfileViewModel(userProfile: userProfile, logger: logger)
  }
}

The fourth and final rule to keep in mind when working with this pattern is that you should always have default values for every property, even if it doesn’t make much sense. This value can never be another builder though, you don’t want to create instances of objects in a builder’s build() method because that would violate rule number three. Of course, you can use builders to create instances as I did in the previous example with the following line of code: var logger = LoggerBuilder().build(). The following code snippet shows an example of using builders the wrong way:

// Don't do this!
class ProfileViewModelBuilder {
  var userProfile: UserProfile = MockUserProfile()
    var loggerBuilder = LoggerBuilder() 

  func build() -> ProfileViewModel {
    let logger = LoggerBuilder().build()
    return ProfileViewModel(userProfile: userProfile, logger: loggerBuilder.build())
  }
}

By using builders instead of concrete objects, you lose the ability to properly configure and control a builder. There might be cases where you want to pass the same instance of a logger to several builders for instance, or you might want to keep a reference to a logger in your test to ensure that a certain object uses the logger correctly. This would be very hard if a builder creates new instances of the logger when you don’t expect it to.

If you keep these four rules in mind while writing builders for your own test suite, you should be able to improve your test suite’s readability and flexibility in no time!

In summary

I hope that this post has given you some insight into the builder pattern and how you can use it to make improvements to your test suite. From my experience, the builder pattern is very powerful for both small and large projects but it does take some getting used to at first. I would like to recommend that you carefully start introducing builders for simple objects in your test suite before refactoring large complicated sections of your test code since that, like any big refactor, can prove to be quite the challenge.

Once you start adopting builders, take a moment to appreciate your test code, you should find that your test code contains less boilerplate, less configuration and setup than it did before, allowing you to focus on what matters, the test itself. The less code you have to look at, the easier it is to understand the purpose of a test and the Builder Pattern is just another tool to achieve this kind of clarity.

I hope this blog post inspires you to make improvements to your test suite. If you have questions, doubts or if you want to let me know that this post helped you, don’t hesitate to reach out on Twitter

Cleaning up your dependencies with protocols

If you’re into writing clean, testable and maintainable code you must have come across the term “Dependency Injection” at some point. If you’re not sure what dependency injection is, that’s okay. I will explain it briefly so we’re all on the same page before we get to the main point of this post.

Dependency Injection in a Nutshell

Dependency injection is the practice of making sure that no object creates or manages its own dependencies. This is best illustrated using an example. Imagine you’re building a login page for an app and you have separate service objects for registering a user and logging them in. Personally I like using an MVVM-ish approach in my apps so I would wrap these services in a LoginPageViewModel. This would leave you with roughly the following code:

// NOTE: this snippet omits parts of the code that I consider non-essential to explaining the practice of Dependency Injection. Copy and pasting this snippet won't work.

class LoginViewController: UIViewController {
  let viewModel: LoginViewModel
}

protocol LoginService {
  func login(_ email: String, password: String) -> Promise<Result<User, Error>>
}
protocol RegisterService {
  func register(_ email: String, password: String) -> Promise<Result<User, Error>>
}

struct LoginViewModel {
  let loginService: LoginService
  let registerService: RegisterService
}

Notice how none of these definitions create instances of their dependencies. This means that the object that is responsible for creating a LoginViewController is also responsible for creating (or obtaining) a LoginViewModel object. And since LoginViewModel depends on two service objects, the object that creates a LoginViewModel must also be able to create (or obtain) the service objects it depends on.

Using dependency injection makes your code more flexible, testable and future proof, and it’s considered good practice amongst practically all areas of software development. However, it has its imperfections and downside, especially in Swift where we don’t really have great support for dependency injection libraries like you might find in, for instance, Java.

Cleaning up your dependencies

As your app grows, you’ll typically find that the number of dependencies that you manage in your application grows too. It’s not uncommon for a single object to (indirectly) depend on a dozen other objects that must be injected into the object’s initializer. This leads to unwieldy initializers which is can be hard to read. On top of this, it makes writing tests more tedious too because if you want to test an object with many dependencies, you’ll have to create an instance of each dependency in your test.

Cleaning up common dependencies is sometimes done by creating one or more dependency containers that might look a bit like this:

struct Services {
  let loginService: LoginService
  let registerService: RegisterService
  let feedService: FeedService
  let shopService: ShopService
  let artistService: ArtistService
  let profileService: ProfileService
}

When using this approach you might inject the entire Services object into the initializer of a LoginViewModel and extract the required services there:

struct LoginViewModel {
  let loginService: LoginService
  let registerService: RegisterService

  init(services: Services) {
    loginService = services.loginService
    regsisterService = services.regsisterService
  }
}

While this solves the problem of having large initializers, it doesn’t solve the problem of having to create many dependencies when you’re writing tests. In fact, this problem is now worse because instead of only having to set up the two services that the LoginViewModel depends on, the entire Services container has to be created. It also breaks encapsulation in some ways because LoginViewModel now has implicit access to all services instead of just the ones that it depends on.

Luckily there is a neat way to get the best of both worlds by composing protocols together and using a typealias. It’s quite simple really, so here’s what I mean.

typealias LoginViewModelServices = LoginService & RegisterService

extension Services: LoginViewModelServices {
  func login(_ email: String, password: String) -> Promise<Result<User, Error>> {
    return loginService.login(email, password: password)
  }

  func register(_ email: String, password: String) -> Promise<Result<User, Error>> {
    return registerService.register(email, password: password)
  }
}

struct LoginViewModel {
  let services: LoginViewModelServices

  init(services: LoginViewModelServices) {
    self.services = services
  }
}

The above code defines a typealias that composes the two dependencies that LoginViewModel has into a single definition. Services is then extended to implement proxy methods for the register and login methods, forwarding them directly to the relevant services, making it conform to LoginViewModelServices and only exposing the methods that are required to make the LoginViewModel work.

This approach neatly wraps up dependencies, making it agnostic of the underlying details of how services are created and managed without exposing too much information to dependent objects. Writing tests for the LoginViewModel is also simplified right now because you can create a single object that conforms to LoginViewModelServices instead of having to create two or more separate objects that might have dependencies of their own.

Of course, this approach might not always work in every context but I’ve personally found that this approached has allowed me to write both cleaner code and cleaner tests. I hope that you’ll find a use for this neat little trick in your own projects and that it allows you to make your code a little bit better just like I have. Don’t hesitate to reach out on Twitter if you have any questions, compliments or other feedback on this post!

About my iOS development book…

It's been almost two years since I blogged on this page. I know, two years is a long break for a person that claims to love "Writing about my everyday coding problems and solutions". Well, there is a very valid reason for my absence because I have been working on a book! Two actually, but they're mostly two sides of the same coin. My first book ever is named "Mastering iOS 10 Programming". It's been published by Packt Publishing and with it you can learn all the awesome new iOS 10 goodies that Apple introduced last year.

9359 OS_ B05645 Mastering iOS 10 Programming

If you're about to go ahead and get this book, wait just one more second. As I said, this is my first book and it covers last year's material. If you want to learn all the ins and outs about iOS that any iOS master should at the very least be familiar with, go ahead and click the image below to get my latest book "Mastering iOS 11 Programming".

B08200

Okay, that was the short pitch. If it's bit tougher to convince you to get my book, allow me to explain what you'll gain from reading this book and then offer you the purchase link again. Sounds fair?

When I wrote my "Mastering iOS" books, I really wanted to write a book that I would personally pick up and read. This means that I focussed on creating content that truly prepares you to do a project that will go to the App Store some day. Each chapter features one of several apps that you'll build throughout the book. The code you write evolves and you'll refactor your code all the time to make sure it works well and is as easy to maintain as possible. The benefit in this is that you won't be writing any crazy or contrived code, just to proof a point. If something is truly an edge case, or if you'll hardly use an API when you're working on your own apps, this book will only cover it as brief as possible. This ensures that any lesson you learn helps you push your career as an iOS developer forward.

A lot of iOS developers nowadays worry a lot about their application architecture. Do we use VIPER, MVVM, plain old MVC or something else? The answer to a question like that is extremely complex because there are so many variables involved. This is why my book doesn't cover any of these architectures. You'll write MVC code since that's what iOS promotes at its core. However, instead of tossing all code in the view controller like some people do (causing the much feared Massive View Controller), you'll see how to break parts of your code into sensible modules so that each part of your code is focussed on completing a single task with an implementation that is flexible. Being able to properly separate the concerns in your code will make adapting to new patterns or architectures much easier because you know what good code looks like.

In addition to general purpose knowledge about building iOS apps, you'll of course read about the notification system that was introduced in iOS 10. No book on iOS 11 would be complete without coverage of ARKit or CoreML, so of course you'll learn about those topics in their own dedicated chapters. Some of the other frameworks and APIs that I cover are SiriKit, the drag and drop APIs from iOS 11, iMessage extensions and even Spotlight gets some love.

One final aspect of development you'll jump in to is automated testing. My book will show you a very simple and basic way of testing the modular code you have written throughout the chapters. Also, you'll see how testing your code can uncover maintainability issues that you can solve by refactoring your code to be cleaner and more testable.

Sounds good? Well, here is that link to my book again as promised earlier.

B08200

Cheers!

Enforcing modular code with frameworks in Xcode

Every iOS developer I know dreams of writing code that’s DRY, modular, testable and reusable. While this is a great goal to strive for it’s often quite hard to write code that is completely modular. It just takes one oversight to blow most of the modularity you have achieved right out the window.

One technique that people use to make it easier to write modular code is to try and ensure that a certain part of their code, for instance the networking logic or their models, know nothing about other parts of the app. Again, a great idea but this isn’t really enforced by anything other than you and your team.

Wouldn’t it be great if there was a way to enforce this level of modularity automatically? Well, I have some great news for you. This is entirely possible and once I tried it for myself it was amazing how straightforward the solution actually is to implement. You can add multiple targets to your Xcode project. This can be used to turn certain parts of your code into frameworks which means that these parts of your code live in isolation from the rest of your code.

The outline of setting this up is as follows:
1. Identify code that should live in a framework
2. Add a new framework target to your project
3. Transfer relevant existing code to the framework target
4. Optional if you use Cocoapods: add dependencies to your new target
5. Write code independent from your app
6. Write tests for your framework
7. Use the framework in your app

We’ll go over each of these steps briefly so you get a good feel of how you can adopt this workflow in your own apps.

Identifying code for your framework

The first step to creating a framework is figuring out what code should live in the framework. It isn’t always obvious which parts of your app could be a framework and which parts can’t be. A good way to figure this out is to think about putting a group of files together in a folder. Can you find a couple of related classes that could happily be put together in a folder where they could only be aware of other classes in the same folder? If you can, it’s probably a good idea to put those files together in a framework.

Another way of finding code that could be better off in a framework is by looking at your code. Are there certain parts of your code that are littered throughout your project that would make changing certain things really hard? That could be a problem in the long run and it might very well be that you actually made some decisions along the way that have destroyed the modularity of your code. Moving some of this tightly coupled functionality into a framework could help you rethink the structure of this tight coupling and it could improve your code drastically.

Adding a framework target in Xcode

Once you have figured out which part of your app you want to put in a framework you need to add a new framework target in Xcode. The easiest way to do this is by going to your project’s settings by clicking on your project name in the Project navigator. Next, look for the + button at the bottom of the panel that lists your targets. This will present you with the same dialog that is presented when you create a new project. In the left sidebar pick the Framework & Library option and select Cocoa Touch Framework.

Now confirm your choice and create the framework by following the on screen steps. If you want to write tests for this target, which you should, make sure to select the Add Unit Tests checkbox. After creating your framework, it is automatically linked to your main app and two new folders were created. One for the framework and one the framework tests.

Adding code to your framework

If you are transferring existing code to your framework, drag the files from your main project folder to the framework folder so your code is logically organised. Next, select the files you just transferred and open the sidebar on the right side of Xcode. Look for the Target Membership header in the File Inspector. You’ll see that the checkbox next to your app is checked. Uncheck this checkbox and check the one next to your framework’s name. This will link the code to your framework instead of your main app.

When you create new files, make sure that the Target Membership is set correctly. Usually Xcode is smart enough to see which folder is currently active and it will add the code to the correct target. It’s always a good idea to double check because you don’t want to go hunting for issues only to find out you forget to correctly set the target for your files.

Integrating with Cocoapods

There’s a good chance your framework has some dependencies. If you’re writing an API framework, you could have a dependency on Alamofire or maybe SwiftyJSON. Cocoapods only links to one framework at a time so your Podfile needs to be updated so it can handle your new framework target. Setting up a Podfile with multiple targets can be done with the following skeleton.

target 'MyApp' do
    PODS GO HERE
end

target 'MyFramework' do
    PODS GO HERE
end

This is very similar to the Podfile you probably already have, expect it has one more target; your framework. Cocoapods will set up your framework target just like it sets up your app, you don’t need to do anything special if you’re adding Cocoapods to a framework.

Writing code independent from your app

Now that you’re all set up, you can start writing your framework code. You do this the same way you’re used to except there is one major difference. In a framework, any code you want to expose to your main application should be marked as public. Code that isn’t marked as public is considered internal and can only be accessed by your framework. Code marked as private still works the same, it can only be accessed by code that lives in the same file.

The big upside of this is that your app can’t know more about the framework then it should. That’s already a big win in terms of modularity.

Writing tests for your framework

Because your tests can only access the public code in your API it’s wise to use your tests as the place where you develop and test your framework. By this I mean that your tests will be the first client that uses your framework. Developing your framework like this makes sure that your framework has great test coverage and you’re testing your framework in isolation from the rest of your app. This forces you to think about your framework instead of the entire app.

Using the framework in your app

Since Xcode has already linked your framework to your app, using your framework works just the same as using any other framework you’ve used. Any file that uses your framework needs to add an import for the framework at the top of the file and from that point out your framework is available to rest of your code.

In conclusion

As you’ve seen, adding your own frameworks to your project isn’t very complex and it forces you to think of your app in a different way. Instead of creating an app where any object can use and access almost any other object you’re creating an app and one or more frameworks. Each of the frameworks you create can function independent from the rest of your app. This means that you could eventually add the framework to other projects or even open source it if you’d like.

Testing your framework is also a lot easier because you know which parts of codes are the API that’s public and those should be the first parts you test. If all you write tests for is your public API, you know that using your framework should work as expected and intended before you even use it in your app.

The approach outlined in this post is especially useful if you only want to use your frameworks in a single app. Using them in multiple apps would require a slightly different approach because you would want the frameworks to live outside of your main project but the benefits and most steps should be very similar.

If you have any feedback, questions or want to discuss this post with men feel free to reach out on Twitter or in the ios developers slack channel

Surviving a start-up’s bankruptcy

On a Tuesday almost two months ago, near the end of april, me and my coworkers received an email about an important meeting the next. We knew that something was going on, the look and feel of this email wasn't the same as usual. This one seemed a bit darker, a bit more serious. On Friday you could feel the tension in the office, people were speculating a bit and just acting different than usual. But we all had jobs to do and we tried to do them just like we always did. But it turns out that this tension and the feeling we al had wasn't wrong.

When the meeting actually went down we heard that an investor had backed out of our start-up. Resulting in an inability to pay the bills and sending all of us home until we would know more. What followed was a pretty strange, exhausting and tough period where I learned new things about myself, my work and how to keep busy. I would like to share this experience with you in this blogpost to try and explain how weird of a period bankruptcy can be from an employee's perspective.

Stage one: registering the events that happened

Since the big announcement was made on a Friday, we actually had a few drinks afterward. It was different than usual, but we had fun, we laughed, talked about how much of a great time we had and that it wasn't over just yet! We could still be bought, an investor might pop up soon and we'll all be back to work in no time. Then Monday came along and I didn't have to go to work. There really wasn't much for me to do actually. So I started my week with just taking the day off. In the back of my mind I had this idea that I was getting payed anyway, so I might as well enjoy this time off.

At first I did pretty well, the first couple of days were pretty laid back, I started working on a side project called "Cijfer Hulp". It's a simple app for Dutch students to keep track of their grades and what grade they need to maintain a great average. But after a couple of days I realised that my job probably wasn't going to come back. This was a pretty huge blow, I loved my job! I enjoyed going there every single day, and to realise that a 10 minute meeting was the last thing I'd ever do at this company was a pretty big blow.

Stage two: finding purpose, keep going

When I established with myself that I was probably going to be out of a job soon I started to look for a new job. This went pretty well at first, a few companies responded to my applications rather quick and I had set up some meetings in no time. However, I felt like I lacked a purpose. My side project was finished in about 8 days so there wasn't much for me to do either. Staying in bed until 10:00AM, 11:00AM or later started to become easier and easier and falling asleep at night became harder and harder. I grew frustrated and irritable very quickly and while the meetings with potential employers were fun, they didn't give me a sense of security.

The fact that I had no job, a few potential employers and the possibility of choosing one to work for and not knowing when I would know more about my current job was troubling me. One of the things that kept me thinking was the fact that my current employer still didn't officially go bankrupt. We were all sitting at home, waiting for the court to pass a verdict. Three weeks went by with no news. It was just about time for us all to get payed, but the money wouldn't come since there was no money. In The Netherlands there's a company that will take over all of the salary payments from an employer if they can't pay anymore, but this only happens after the court has declared bankruptcy. At this point it was clear that verdict would have to become bankruptcy. It was just a matter of when.

During this first month I had days where I was just frustrated, grumpy and tired all day. Keeping myself busy just felt pointless. I lacked purpose, everything I did was just filler to get through another day of not having to do anything. On other days I was motivated, I though about maybe going freelance or starting another side project. These days were quite fun actually because they had purpose and meaning. Whenever I'd go and have a cup of coffee at some company I always felt pretty satisfied, I was working towards something. However, my overall mood wasn't too good. Having no responsibilities or purpose is taxing and I wouldn't recommend it to anybody. Doing small side projects is a smart idea. What also helped was to just head out of the house around 09:30 and go to the library to work there. Whenever I did this I was at least double as productive compared to staying at home all day.

Stage three: something look forward to

After a little longer than a month I found an employer that I wanted to work for. And they were excited to hire me as well! This felt like a huge win. No matter what was going on at my current job, I knew what was next. And the best part, just a few days after this I also got the news that me and my coworkers were now officially fired and the company had been declared bankrupt. However weird it may seem I was very relieved with this letter. Finally some closure, finally a timeline for it all. Just one more month and then I would start at my new employer, knowing that the current situation would be fully handled and I could finally start working towards getting the salary I still needed from the month of sitting at home. All of this had been so frustrating, especially not knowing what's next and when it was coming. So for all of this to fall in place so short after one another was truly a blessing.

Tips for people who might find themselves in a similar situation

My most important tip is to try and keep up some sort of schedule. Your work rhythm probably provides some stability to you and your mind. Don't break this, try to go to a public library or if you're comfortable working from home, try to spend the day working on things. Maybe a side project, maybe some blog posts or maybe do some chores that you needed to get done anyway. You don't have to spend your whole day programming, just make sure you're busy.

Also, i would recommend to start looking for jobs right away. Just go and have some cups of coffee with people. You don't have to formally apply everywhere, just get to know some people. Expand your network. It might seem a bit pointless and hard at times, but it's really worth it. The nice thing about being in this situation is that there's no rush in finding a new job. You can take it easy, you can really browse around for a nice place to work at.

It's okay to be sad or feel down about the situation. When I had a bad day sometimes I thought that I had messed up. I should have been able to see this coming or do something, or whatever. It's tough to realise that it's something you might not have been able to see coming, something that you lack control over and it's okay to be bummed out. If you loved your job it will have huge impact on you when that suddenly disappears. This is also the reason why I recommend to try and keep up our rhythm. It will help to keep your mind from wondering and it will help you wit that feeling of having no purpose.