Sunday, 26 November 2017

Using Swift 4's Codable protocol to configure your UI test environment

TL;DR - Take advantage of the new Swift 4 Codable protocol to encode the launch environment of your UI tests.

Native UI testing in iOS does not allow direct interaction from the UI test to the app target. In other words, the test code cannot change the state of the app code while it is running. 
XCUITests allow for information to be sent to the app by either the launchArguments: [String] or the launchEnvironment: [String : String]. These 2 properties can be read from the ProcessInfo. Historically, I've used the launchEnvironment to send specific flags, for example ["UITest-has-completed-onboarding": "true"]. However, this can get messy as more options are required and a lot of code is needed to be able to send more complex data. 
The introduction of Codable in Swift 4 provides a much simpler approach for this kind of communication. In essence, a type that represents the launch environment can be encoded and decoded with very little effort thanks to Codable.


The example

Define a UITestEnvironment type that conforms to Codable with any relevant data for your UI test environment. For example:
Note: This type has to be included in both the app target and the test target.
struct UITestEnvironment: Codable {

    static let Key = "UITestEnvironmentKey"

    let hasCompletedOnboarding: Bool

    // Any other keys or data you'd like
}
Add a function to encode an Encodable type into a base64 JSON string to your test target:
extension Encodable {
    func base64EncodedJSONString() -> String? {
        guard let encodedData = try? JSONEncoder().encode(self) else { return nil }
        return encodedData.base64EncodedString()
    }
}
Add a function to decode a Decodable type from a base64 JSON string to your app target:
extension Decodable {
    static func decode(from base64EncodedJSONString: String) -> Self? {
        guard let jsonData = Data(base64Encoded: base64EncodedJSONString) else { return nil }
        return try? JSONDecoder().decode(self, from: jsonData)
    }
}
On your UI tests create the environment you need for that test, encode it and pass to the launchEnvironment:
let originalArguments = UITestEnvironment(hasCompletedOnboarding: true)
let encodedArguments = originalArguments.base64EncodedJSONString()!

let app = XCUIApplication()
app.launchEnvironment = [UITestEnvironment.Key: encodedArguments]
app.launch()
Read the launch environment from ProcessInfo and decode the data into UITestEnvironment on the app target where it is relevant to alter the state of the running app:
if let encodedEnvironment = ProcessInfo.processInfo.environment[UITestEnvironment.Key],
    let decodedEnvironment = UITestEnvironment.decode(from: encodedEnvironment) {
    // Do something with the test environment
}
That's it! This is a very simple way to transmit information between your UI tests and your app. Since the only requirement for a UI test environment is that it conforms to Codable you may have multiple types for different tests instead of one UITestEnvironment.
I’d like to thank Nahuel Marisi for reviewing this article.

Tuesday, 3 October 2017

2 years later

Today marks the second anniversary of marisibrothers.com, a blog by my brother and myself. I've learned a lot from reading blogposts, so creating a blog to share knowledge in this format made sense.
We chose Blogger to host it with Google Analytics because it was easy to get started. I've found Blogger is ok to begin with, the main difficultly is changing the layout of the blog. All the blog urls point to our own domain and we write our posts in markdown, meaning we could easily migrate to another provider should we wish to.
Originally, we started doing one post every week, alternating between my brother and myself. However, we found it hard to keep both the pace and the quality of the content. We now aim for one post a month.
We work in software development, so the content has been around this with a focus on iOS. Some posts have been specific, others high-level and one has become an open source library.
A few stats as of today (3rd October 2017):
  • 20 posts by Luciano 
  • 12 posts by Nahuel
  • The most popular post has 11,000+ views, interestingly Swift 3.2 made it's content obsolete
Finally, I’d like to thank the following people for being kind enough to review my posts over the years (alphabetically ordered):
It took years to start a blog but I'm happy we did. I encourage you to write about anything you find interesting.

Wednesday, 20 September 2017

Learning a new programming language today

TL;DR - Understand the core concepts of a language and then alternate between learning details and putting them into practice
A language is a means to an end. Quickly picking up programming languages allows developers to build anything. I've recently been learning Java to contribute to a Spring backend. I've found that once the foundations of the language have been learned, a great way of learning is to develop a process of cycling through learning details, then putting them into practice. 

Getting started - Understand core principles

The first thing to do is understand the core concepts of the language and the main use cases. If you can, get an experienced engineer to mentor you. This way you'll cover the mundane setup stuff and be running code in no time. Spend about a day or two here, enough time to know everything to get you started but not too much that you end up bored and lose motivation.
Ask yourself the following questions:
Most of the above high-level questions don't have an absolute answer which is why exploring these questions and answers is key. This will allow you to establish strong foundations, on which to learn the details.

Learn the details

At this point you'll hopefully have some vague idea of what the language does and how to execute some code. So now it's time to get to grips with how to write it.
  • Learn some syntax, for example:
    • How are variables and functions declared?
    • What are the available control flows? e.g. if statements, for loops
    • What are the core data structures and how do you create them? (e.g. arrays and dictionaries)
  • What kind of features does it have? For example:
    • Does it have reference and value types? And how are they used?
    • Can you define interfaces/protocols?
    • How do you write concurrent code?
    • If it's strongly typed, does it have generics?
  • What's available in the language's standard library?
  • What are the main conventions people follow?
    • Check a code style guide, for example
    • Do developers rely on 3rd party libraries? If so what the most common ones? For example, I've found that modern Java codebases use RxJava

Dive in head first

Theory is great, but we learn much more through experience. Nobody learns how to ride a bike by reading a book about it. Try out one of the following in order to gain experience:
  1. Contribute to an existing project at your workplace, pair with another developer if you can.
    • I've found that going into an established codebase where good practices are followed has been awesome. It'll be easier to add new small features by extending existing code or by following existing patterns.
    • Code reviews by other developers will help point out issues quickly.
  2. Contribute to an existing open source project. It's common for projects to mark issues that outsiders can pick up, this is a great place to start.
  3. Create your own project. Find something you're keen on creating and build it with the language you're learning.
Lastly, stay out of your comfort zone and push yourself to constantly learn.
I’d like to thank Emily Woods for reviewing this article.

Tuesday, 16 May 2017

Lazy collections

Lazy collections

TL;DR; The lazy evaluation of collections can improve the performance of your app when working with large collections.
Swift introduced the possibility of lazy evaluation in our code. While many people seem to be aware of lazy variables, I find fewer users of lazy collections. In this brief article, we'll look at how we can use lazy evaluation with collections, which can bring performance benefits when dealing with particularly large collections.

Lazy map

Let's have a look at what happens when we ran map on a standard array.
let array = Array<Int>(0..<1000)
let mappedArray = array.map { (value: Int) -> Int in
    print("incrementing: \(value)")
    return value + 1
}

print("First element mapped: \(mappedArray[5])")
In here, map will apply our closure to every single element of the array, even though we're only interested in the fifth one. If you run this code in the Playground, the output should be something like:
incrementing: 0
incrementing: 1
incrementing: 2
incrementing: 3
incrementing: 4
    ...
incrementing: 999
First element mapped: 6   
The larger the array is, and the more computationally intensive your closure is, the more pointless work you end up doing if you're not interested in all of the element of this array.

Using a lazy collection

Every collection provides the lazy property that gives us a "view" into this collection, that lazily provides higher order operations like map and filter. The actual type of the lazy property is LazyMapRandomAccessCollection. Let's go back to our original example, but use lazy instead this time:
let array = Array<Int>(0..<1000)
let mappedArray = array.lazy.map { (value: Int) -> Int in
    print("incrementing: \(value)")
    return value + 1
}

print("First element mapped: \(mappedArray[5])")
Output:
incrementing: 5
First element mapped: 6
This time, map is only applied to the element we're interested (fifth), saving us a fabolous amount of pointless work.

Filter

Just as you can use map with lazy collections, you can also use filter. Let's have a look at a quick example:
let array = Array<Int>(0..<1000)
let filteredArray = array.lazy.filter {
    print("filtering: \($0)")
    return $0 < 10
}

print("first filtered result: \(filteredArray.first!)")
Output:
 filtering: 0
first filtered result: 0
As we see, filtering only runs once (for the first result), instead of the 1000 times it would run if we were not using a lazy collection. It's worth noting that filter returns LazyFilterBidirectionalCollection, which unlike its random access counterpart does not accept an integer as a subscript. 

Prefix

A lazy filter can easily be combined with the prefix function to limit the number of results filter returns. It's often the case that we're only interested in the first occurrence of an object in a collection. By using evaluation and prefix we can stop as soon as we find the first occurrence. Without using a lazy collection, filter would still go through the whole collection. 
let array = ["green", "blue", "red", "orange", "green", " purple", "red"]
let filteredSequence: AnySequence = array.lazy.filter {
    print("filtering: \($0)")
    return ($0 == "red")
}.prefix(1)

print(Array(filteredSequence))
Output:
filtering: green
filtering: blue
filtering: red
["red"]
Note here that we're making sure that our collection is evaluated as a sequence. There are two prefix versions. The collection one which returns a BiDirectionalSlice and the sequence one which returns AnySequence. Only the sequence version evaluates lazy, while the collection one will iterate through the whole collection. The drawback of using a sequence is that we lose the use of subscripts.

Monday, 3 April 2017

Memory leak in Swift: Assigning a function to a closure

TL;DR - Assigning a function to closure property creates a strong reference to the owner of the function potentially creating a retain cycle
Swift has first class functions, meaning that a function is treated like any other object, i.e. it's possible to:
  • - Pass a function as an argument into another function 
  • - Return a function as a value from a another function
  • - Assign a function to a variable 
  • - Store functions in data structures
I have found one caveat related to this. Let's say you have a view that has a closure property that gets called when a button is pressed.
class View {
    var onButtonPressed: (()-> Void)?
}
This View is owned by a ViewController and it handles the button being pressed by assigning it's handleButtonAction function to the onButtonPressed closure property of the View.
class ViewController: UIViewController {
    let customView = View()
    
    init() {
        super.init(nibName: nil, bundle: nil)
        customView.onButtonPressed = handleButtonAction
    }
    
    required init?(coder aDecoder: NSCoder) { fatalError() }
    
    func handleButtonAction() { /* some implementation */ }
}
Since Swift allows for functions to be assigned to closures I thought that customView.onButtonPressed = handleButtonActionwas an elegant way of linking the implementation of the handler, defined in it's own function, to the button action. However, this seemingly harmless code will create a retain cycle. Thanks to Xcode 8 memory debugger it's easy to visualise this:
This happens because when the handleButtonAction function is assigned to the onButtonPressed closure self is implicitly captured since self is the owner of handleButtonAction. The strong reference to self from the handleButtonAction function is indicated by the blue arrow.

Unit testing the retain cycle

While finding a solution to break this cycle it's good to have a unit test that proves this. The following test will fail if the ViewController has a retain cycle:
func testViewControllerNotRetained() {
    // Create two variables for the view controller,
    // one strong and one weak
    var sut: ViewController? = ViewController()
    weak var weakSut = sut
    
    // Nilling out the strong reference should release the object,
    // making the weak reference also nil
    sut = nil
    XCTAssertNil(weakSut)
}

Breaking the cycle

A solution to this problem can be to assign a new block that captures self weakly and call the function inside it using the weak self:
view.onButtonPressed = { [weak self] in
    self?.handleButtonAction()
}
In this case we can go for unowned since the View will not exist beyond the lifecycle of the ViewController:
view.onButtonPressed = { [unowned self] in
    self.handleButtonAction()
}
This solution is certainly less elegant than the original direct assignment. This is why it's so easy to forget that assigning a function retains the owner of that function potentially creating a retain cycle.
I’d like to thank Nahuel Marisi and Neil Horton for reviewing this article.