More XCTest UT Testing: A Helper function to scroll to a cell in a UICollectionView

At Luma Touch, we continue to use (and highly recommend) fastlane (now a part of tools) to create and upload builds, manage App Store metadata, and most importantly, create and upload screenshots to the App Store.

The most difficult part of creating screenshots is setting up the XCTest automated tests in XCode to get everything in the right ‘place’ for each screenshot.  My previous post discussed a number of hints and tips and showed a complete example of how to do this.

For our next app, a large part of the screenshot setup requires selecting effect presets from a collection view, and scrolling the collection view to the correct location.  This is made particularly difficult since each device has a different sizes for the collection views and different sizes for the cells within them.  After a number of tries at guessing the right distance to ‘swipe’ with coordinates that would work for all devices, I ended up writing a new helper function that would automate scrolling to a particular cell within a collectionView.

The scrollTo Helper Function

The function looks like this (full source at the bottom of this post):

func scrollTo(cellIdentifier: String, collectionViewElement: XCUIElement, scrollUp: Bool = false, fullyVisible: Bool = false) -> Bool

To use it in your test code, your UICollectionView and each cell should have its accessibilityIdentifier set in code.  I usually include the section and item in the accessibilityIdentifier for the cell (i.e.: “presetcell-0-20”).  So, to scroll to a cell in a collectionView with an accessibilityIdentifier of “presets”, you could use:

scrollTo("presetcell-0-20", collectionViewElement: app.collectionViews["presets"])

This will scroll downward through the collectionView until “presetcell-0-20” is hittable.  If you wanted to make sure that the cell is fully visible (for a screenshot for example), you would use:

scrollTo("presetcell-0-20", collectionViewElement: app.collectionViews["presets"], scrollUp: false, fullyVisible: true)

And, finally, if you want to scroll upwards to “presetcell-0-5” and make it fully visible, you would use:

scrollTo(“presetcell-0-5”, collectionViewElement: app.collectionViews[“presets”], scrollUp: true, fullyVisible: true)

An Important Note About Cell accessibilityIdentifiers

In my previous post, I noted how I cleared the accessibilityIdentifier in tableView:didEndDisplayingCell.  However, this has a small chance of confusing the scrollTo helper function, so I’ve changed to setting the accessibilityIdentifier uniquely in didEndDisplayingCell like this:

cell.accessibilityIdentifier = [NSString stringWithFormat:@"notvisible-%ld-%ld", (long)indexPath.section, (long)indexPath.item];

How The Helper Function Works

The helper function scrolls 1/2 the height of the collection View over and over until either the cell you’re looking for is hittable, or the scroll doesn’t actually change anything (you’ve hit the top or bottom of the collection view).

Note that the first check it does for the cell, looks like this:

collectionViewElement.cells.matchingIdentifier(cellIdentifier).count > 0

This lets you query the collectionView cells to see if the identifier is present without having the test fail by directly checking for the cell with collectionViewElement.cells[cellIdentifier], you would get a failure in the test, and it wouldn’t continue.

The code checks to see if the touch changed anything by keeping track of the ‘middle’ cell in the list of cells for the collection view (which by-the-way, might include cells that are no longer displayed), and determines if it’s the same cell id and same frame to see if anything has changed.

After the cell is found to be hittable, if you want it fully visible, there is a second loop that scrolls up or down by a smaller amount (1/2 the height of the cell) until the cell’s frame is fully contained by the collection view’s frame.

The Helper Function Source

    func scrollTo(cellIdentifier: String, collectionViewElement: XCUIElement, scrollUp: Bool = false, fullyVisible: Bool = false) -> Bool {
        var rtn = false
        var lastMidCellID = ""
        var lastMidCellRect = CGRectZero

        var currentMidCell = collectionViewElement.cells.elementBoundByIndex(collectionViewElement.cells.count / 2)

        // Scroll until the requested cell is hittable, or until we try and scroll but nothing changes

        while (lastMidCellID != currentMidCell.identifier || !CGRectEqualToRect(lastMidCellRect, currentMidCell.frame)) {            

            if (collectionViewElement.cells.matchingIdentifier(cellIdentifier).count > 0 && collectionViewElement.cells[cellIdentifier].exists && collectionViewElement.cells[cellIdentifier].hittable) {
                rtn = true

            lastMidCellID = currentMidCell.identifier
            lastMidCellRect = currentMidCell.frame      // Need to capture this before the scroll

            if (scrollUp) {
                collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.4)).pressForDuration(0.01, thenDragToCoordinate: collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.9)))\
            else {
                collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.9)).pressForDuration(0.01, thenDragToCoordinate: collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.4)))

            currentMidCell = collectionViewElement.cells.elementBoundByIndex(collectionViewElement.cells.count / 2)

        // If we want cell fully visible, do finer scrolling (1/2 height of cell relative to collection view) until cell frame fully contained by collection view frame

        if (fullyVisible) {
            let cell = collectionViewElement.cells[cellIdentifier]
            let scrollDistance = (cell.frame.height / 2) / collectionViewElement.frame.height

            while (!CGRectContainsRect(collectionViewElement.frame, cell.frame)) {   
                if (cell.frame.minY < collectionViewElement.frame.minY) {
                    collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.5)).pressForDuration(0.01, thenDragToCoordinate: collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.5 + scrollDistance)))
                else {
                    collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.5)).pressForDuration(0.01, thenDragToCoordinate: collectionViewElement.coordinateWithNormalizedOffset(CGVector(dx: 0.99, dy: 0.5 - scrollDistance)))

        return rtn;


XCTest UI Testing Hints and Tips

As I’m writing this, I’m watching fastlane’s snapshot tool generate 900 snapshots (3 app variants, 6 devices, 5 screenshots per device, 10 languages) slowly in the background while I work on other things.  If you haven’t looked at fastlane yet, you should (, it’s an incredible timesaver in distributing beta builds, managing metadata and screenshots for the app store, and much more.

Fastlane’s snapshot tool was recently modified to use the new XCTest UI Testing (replacing the older Instruments Javascript based UI Testing).  In the long run, this is a great thing.  The new UI Testing has a lot of promise, but it it’s still not documented and has a number of issues that can make it frustrating to use. I wrote this blog based on some issues that I struggled with and resolved in creating the screenshot code for snapshot.  I’m hoping others will find this useful.

In my own research to resolve problems, I found the following sites and articles extremely helpful in learning more about the UI Testing framework: – Multiple articles and basic documentation of UI Test classes

UI Testing Gotchas at Big Nerd Ranch

UI Testing in Xcode at Infinity Learning

XCode 7 UI Testing, a first look at mokacoding

I would recommend reading these sources to get a better overall understanding, since this blog focuses on some specific issues and solutions rather than documenting the basics of UI Testing.

Adding Test Files To Your App

The first thing I needed for my screenshots was to be able to add a number of test files, including photos and videos that needed to be in the Photos app on the simulator.  In the previous version of snapshot, I could copy the files as part of the Snapfile script, but that isn’t possible now.  So, for this version, I added a Run Script action in the UI Test target‘s Build Phases that copies the files into the app itself:

cp -R "${HOME}/Dropbox/LumaTouch/Product Assets/PinnacleStudio/Screenshot-Projects/SnapshotFiles/" "${BUILT_PRODUCTS_DIR}/"

When the app is built for the simulator, it contains code that looks for the SnapshotFiles folder, and if found, it copies some of its data into the App’s documents folder, and for photos and videos, calls PHAssetLibrary to add the photos and videos to the Photos app.  The code looks for the SnapshotFiles folder like this:

NSURL *folderUrl = [[NSBundle mainBundle] bundleURL];
folderUrl = [folderUrl URLByAppendingPathComponent:@"SnapshotFiles"];
if ([[NSFileManager defaultManager] fileExistsAtPath:folderUrl.path])

Accessibility To Identify Elements

The best way to reference UI elements in UI Testing is through accessibility values.  Elements like StaticText (UILabel) elements can automatically be referenced by the text value of the label, which effectively becomes the accessibilityLabel value of the element like:

let labelElement = app.staticTexts["Phone Number"]

However, this is not very useful if your app is localized and the label changes based on the language.  I prefer to set the accessibilityIdentifier for each UI element in the app and use that to reference elements when testing.  The accessibilityIdentifier is an internal identifier and is not localized.  You can set this in Interface Builder, or in code, like this:

phoneLabel.accessibilityIdentifier = "phone-label"

Then, to access in your test, simply use the accessibilityIdentifier, like this:

XCTAssert(app.labels["phone-label"].title == "Phone Number")

Waiting for UI Elements to Appear or Disappear

One of the issues with adding my test files for screenshots is that it may take some time for the app to copy the files and add the media to Photos.  Originally I put a sleep(30) as a guess in my test code, but there is a better way.  I added code in the app to create a hidden button once it was finished setting up the test files.  I created a number of helper functions (code for these helper functions is at the bottom of this post) to wait for elements to exist, or be hittable, or to disappear again.  These were simply added as extensions to XCTestCase in my test code.

  • waitForHittable(element: XCUIElement, waitSeconds: Double) – Wait for an element to exist and be hittable (visible and onscreen)
  • waitForNotHittable(element: XCUIElement, waitSeconds: Double) – Wait until an element is no longer hittable (might still exist, but is either not visible or not onscreen)
  • waitForExists(element: XCUIElement, waitSeconds: Double) – Wait for an element to exist (does not need to be visible or onscreen)

All of these functions take advantage of the waitForExpectationsWithTimeout method in XCTestCase and make it easy to wait for certain things to happen within an allotted time.  So, in my case, I have the following code in my test to wait for the test files to be finished:

waitForExists(app.otherElements["snapshotReady"], waitSeconds: 60)

As soon as the “snapshotReady” view is created and added as a subview in my app’s code (it’s hidden, and created with a rect that’s offscreen, so it’s never seen on the UI), the test continues.  If the processing of the snapshot test files fails, then after 60 seconds, the test will fail.

In another point in my test code, I need to start a render process, which brings up a progress view with a cancel button.  In my old test code, I just put in a long sleep() to make sure it could finish, but with the wait helper functions, I can wait until the progress view appears, then disappears again to continue:

waitForHittable(app.buttons["export-process-cancel"], waitSeconds: 5)
waitForNotHittable(app.buttons["export-process-cancel"], waitSeconds: 320)

Debugging UI Elements When Testing

The best way to see what is going on is to set a breakpoint in your test code, then output a complete list of the UI Elements that are onscreen.  You can do this in lldb with the following command:

po print(app.debugDescription)

This assumes that app is assigned to XCUIApplication(), which is normally the case. This will print a well-formatted description of the app element and all of its descendants (if you don’t use print(), you’ll get a very ugly output).  You can use this on any XCUIElement(), for example:

po print(app.buttons["edit-render"])

Shortest Path To An Element

When you’re recording tests, XCode might record something like this when tapping on a tableView cell (assuming you’ve set accessibility identifiers or labels on the table and cells):


When you’re writing your own test code, if you know that the accessibilityIdentifier for the cells are unique in the UI, you can shortcut this with:


This is because the cells call simply queries all descendants that are Cell elements, and as long as it finds only one that matches the identifier, that will be the element returned.

Duplicate Identifiers in TableView Cells

When running one of my tests, I kept getting a failure Multiple Matches Found when I tried to tap() a cell in my table.  After a great deal of experimenting I figured out the problem. I was setting the accessibilityIdentifier in cellForIndexPath, but I was never clearing that identifier, and somehow the cached cell, was being found in the query. To solve this problem I added code to clear the accessibilityIdentifier in tableView:didEndDisplayingCell.

Failed To Find Matching Element

A number of times when recording, I got the following message added as a comment in my test code:

Failed to find matching element please file bug ( and provide output from

I tried many different changes of accessibilityIdentifiers and different paths to the element, but nothing helped, so I filed a Radar with Apple.  It was a duplicate, so obviously I wasn’t the only one.  In playing with XCode 7.2 beta 2, it seems to be better about this, but I was still having a problem when calling tap() on cells in some tables.  It wouldn’t fail, but the cell was not being selected.  After a lot of playing around, I finally found the cause of the problem:

Tap Was A Long Press

The table that was failing had a long press gesture recognizer (0.175 seconds) attached (for drag-and-drop), and what was happening is that the tap() call was being picked up as a long press, so the cell wasn’t being selected.  To solve this problem, I changed the tap() to a pressForDuration, like this:


How To Do An Arbitrary Touch or Drag

Without documentation, it’s easy to miss how to do an arbitrary touch or drag in the UI (from/to a particular point on the screen).  For many situations it’s not needed, you can just use the pressForDuration:thenDragToElement call on an element, but I had some situations that weren’t that straightforward.

The solution is XCUICoordinate().  You create an XCUICoordinate() object by calling coordinateWithNormalizedOffset() on any XCUIElement (including XCUIApplication).  The CGVector is a value normalized from 0.0 to 1.0 to represent the element’s rect (you can provide values outside of the rect with negative values and values above 1.0).

The XCUICoordinate() object holds a reference to the XCUIElement() it was retrieved from. It is important to note that when you perform an action with XCUICoordinate() it will calculate the screen point at that moment, so if the element the coordinate references has moved since you first grabbed the coordinate, the tap will be relative to the element’s current location.

To perform a drag with an XCUICoordinate, you can call pressForDuration:thenDragToCoordinate.

You can get the second coordinate the same way you got the first one (by creating it from any element), or you can call coordinateWithOffset(offsetVector: CGVector) on an XCUICoordinate to return a new coordinate offset from the first coordinate (the offsetVector in this case is in absolute points rather than a normalized value).  Here is a complete example of using XCUICoordinate to do a drag:

let startCoord = app.tables["text-album-0-1"].coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.01));

let endCoord = startCoord.coordinateWithOffset(CGVector(dx: 0.0, dy: -100));

startCoord.pressForDuration(0.05, thenDragToCoordinate: endCoord)

This starts the touch in the text-album-0-1 album halfway across the album, and 1% distant from top, then drags 100 points upward.

Conditional Code for iPad and iPhone

I needed some different code depending on whether the test was running on iPhone or iPad, but didn’t want to write separate tests.  You can determine the size class of the app’s window to provide this type of condition:

if ( == .Compact || == .Compact)

More To Come

That’s all of my hints and tips for now.  I’ll create a new blog as I find more hints and tips.  I’m re-creating a suite of hundreds of UI Tests done with OCUnit() back in 2011.  I always find examples the best way to learn something, so I’ve also included a complete example of a test doing a screenshot with fastlanes/snapshot.

Screenshot Test Source Code

func testScreenshot01() {
    let app = XCUIApplication()
    XCUIDevice().orientation = .LandscapeRight;

    waitForExists(app.otherElements["snapshotReady"], waitSeconds: 60)

    if ( == .Regular && == .Regular)
            // iPad Screenshot

            // Select and tap again to edit the project

            // Select the Albums segment, and select album 4


           // Render and wait for completion
            waitForHittable(app.buttons["edit-render"], waitSeconds: 5)
            waitForHittable(app.buttons["export-process-cancel"], waitSeconds: 5)
            waitForNotHittable(app.buttons["export-process-cancel"], waitSeconds: 320)

            // Tap on clip 4 in the storyboard

            // Open the audio mixer
            // Select a video clip for the source viewer
            // iPhone Screenshot

            // Drag upward in the project table to make sure project is visible
            let coord = app.tables["proj-table"].coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5))

            let endCoord = coord.coordinateWithOffset(CGVector(dx: 0.0, dy: -50))

            coord.pressForDuration(0.05, thenDragToCoordinate: endCoord)

            // Select and edit the project

            // Tap breadcrumb to go back to Moments/Albums select

            // Tap on Albums

            // Open album

            // Render and wait for completion
            waitForHittable(app.buttons["edit-render"], waitSeconds: 5)
            waitForHittable(app.buttons["export-process-cancel"], waitSeconds: 5)
            waitForNotHittable(app.buttons["export-process-cancel"], waitSeconds: 320)

            // Tap on clips to get to clip 4

            // Switch to timeline only view

            // Tap in timeline ruler to de-select clip
            app.otherElements["Ruler"].coordinateWithNormalizedOffset(CGVector(dx: 0.1, dy: 0.05)).tap()

            // Open toolbox, tap audio mixer, close toolbox

        // Take the fastlane/snapshot 

        // Get back to projects page

Helper Functions Source Code

extension XCTestCase {
    func waitForHittable(element: XCUIElement, waitSeconds: Double, file: String = __FILE__, line: UInt = __LINE__) {
        let existsPredicate = NSPredicate(format: "hittable == true")
        expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)        

        waitForExpectationsWithTimeout(waitSeconds) { (error) -> Void in
            if (error != nil) {
                let message = "Failed to find \(element) after \(waitSeconds) seconds."
                        inFile: file, atLine: line, expected: true)

    func waitForNotHittable(element: XCUIElement, waitSeconds: Double, file: String = __FILE__, line: UInt = __LINE__) {
        let existsPredicate = NSPredicate(format: "hittable == false")
        expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)

        waitForExpectationsWithTimeout(waitSeconds) { (error) -> Void in
            if (error != nil) {
                let message = "Failed to find \(element) after \(waitSeconds) seconds."
                    inFile: file, atLine: line, expected: true)

    func waitForExists(element: XCUIElement, waitSeconds: Double, file: String = __FILE__, line: UInt = __LINE__) {
        let existsPredicate = NSPredicate(format: "exists == true")
        expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)

        waitForExpectationsWithTimeout(waitSeconds) { (error) -> Void in
            if (error != nil) {
                let message = "Failed to find \(element) after \(waitSeconds) seconds."
                    inFile: file, atLine: line, expected: true)


The pros and cons of Apple’s TestFlight for me so far

I was an avid TestFlight user since 2011. TestFlight made it easy to distribute beta builds to testers. It helped make provisioning with device ids relatively painless, especially with its ability to re-provision a beta with new devices. It was still a bit of a pain though, when users got new devices, there was a bit of a dance that had to be performed, getting the device id, adding that in, then adding the new device to a provisioning profile, and regenerating the profile. And of course there was the yearly 100 device limitation with no ability to remove old devices during the year.

When TestFlight was purchased by Apple and stopped accepting new apps, I switched to Crashlytics Beta (I was already using Crashlytics for crash tracking). It’s been a good replacement for TestFlight.

With the re-release of TestFlight from Apple, I had some hope of simplifying the process, but as always with developer tools from Apple, there are real tradeoffs in what you get. So here is a list of pros and cons with Apple’s TestFlight that I’ve found so far:


– No more worrying about devices! This is the biggest advantage of TestFlight. When you add a user (either an Internal or External tester), you simply add the email address of their Apple ID, and they will be able to install beta builds on their devices (up to 10 per tester).

– It is nice to be able to do testing with Internal testers first (a new submitted build shows up automatically for internal testers), then send out the build to external testers.

– Beta builds appear with an orange dot (and will automatically expire after 30 days), so it’s easy to tell that it’s a beta

– With the addition of Groups, it’s easier to manage external testers across multiple products (though this could still be improved)

– Once you’ve submitted an app for initial review for external testing, subsequent betas can be readied for external review immediately after entering build information.


– Users can only install the latest beta build (they can’t install old builds from the history of builds). This is another big problem if you end up sending out a beta that causes bigger problems than it fixes (not uncommon during betas).

– You can only send out 2 beta builds per day for external beta testing! This is a big limitation when you’re trying to send out quick changes to fix an odd bug that can’t be reproduced in-house

– You must submit the app for review for external beta testing. For the initial submission, it took a few days to get it approved.

– After you submit the build, you then need to go to itunesconnect and submit it for external beta testing, filling in the ‘what to test’, and answering a few questions about changes to the build. I found the process a little cumbersome – would be nice if that info could be filled in during submission of the build (would be nice to have a separate Submit Beta button in XCode)

– Still waiting on any kind of good crash reporting (I won’t be switching from Crashlytics anytime soon)

TestFlight is definitely a major step forward for beta testing of apps for iOS, but there are some difficult tradeoffs right now.  I’ll probably stick with it so I don’t have to worry about managing devices and provisioning, but I’m certainly hoping for continued improvement.

Subclassing UICollectionViewLayoutAttributes Correctly

I had the need to create a custom UICollectionViewLayout and I also needed to subclass UICollectionViewLayoutAttributes to add a representation attribute so I could ‘tell’ each cell to draw itself differently depending on the users’ selection of a view type.

In looking at examples others had provided for subclassing UICollectionViewLayoutAttributes I found a major confusion.  Many developers are trying to use the UICollectionViewLayout’s layoutAttributesForItemAtIndexPath method as a call to create the attributes object, but that method is meant to be called by the UICollectionView to return attributes for a specific item in the collection.

The correct way to create a new instance of custom attributes is to call UICollectionViewLayoutAttributes’ layoutAttributesForCellWithIndexPath class method.  You can call this method with any subclass of UICollectionViewLayoutAttributes to create a instance of your custom attributes (you’ll notice that it has instancetype as its return value, so it returns an instance of whatever class calls the method).

So, to create an instance of my custom layout attributes, I would use:

MyCustomLayoutAttributes *layoutAttributes = [MyCustomLayoutAttributes layoutAttributesForCellWithIndexPath:someIndexPath];

However, if you want to allow your custom layout class to be subclassed and allow the layerAttributesClass method overridden, then you should ask for the current layoutAttributeClass as shown here:

UICollectionViewLayoutAttributes *layoutAttributes = [[[self class] layoutAttributesClass] layoutAttributesForCellWithIndexPath:someIndexPath];
// setup standard attribute parameters in UICollectionViewLayoutAttributes
if ([layoutAttributes isKindOfClass:[MyCustomLayoutAttributes class])
    MyCustomLayoutAttributes *myAttributes = (MyCustomLayoutAttributes*)layoutAttributes;
    // setup custom attributes


A Couple of iOS 7.1 UI Development Surprises (not the good kind)

Custom Track and Progress Images for UIProgressView broken

If you set trackImage and progressImage in UISliders, you’ll find these have broken in iOS 7.1.  They will be ignored and you will get the standard slider (at the standard 2 pixel height) instead.

Accessibility Bold Text affects images drawn with UIImageRenderingModeAlwaysTemplate

We are using ‘template’ images (UIImageRenderingModeAlwaysTemplate) for all of our buttons, so that iOS draws them using the shape of the image and a tint color.  However, in iOS 7.1, if the user turns on Bold Text under Accessibility, then all images drawn with the template rendering mode will have their pixels expanded to simulate a bold look.  For example, here is an image of a UIImageView and UIButton that use UIImageRenderingModeAlwaysTemplate with Bold Text turned off:

normalAnd here is the same app with Bold Text turned on:



So, if you plan on using template images, be aware that they might be affected by accessibility settings.


NSURL fileURLWithPath changes behavior in iOS 7

Another interesting issue found today.  NSURL fileURLWithPath has changed behavior in iOS 7.

Before iOS 7 it would return a fileURL with file://localhost prepended to the path passed in (so passing in “/var/test” would return “file://localhost/var/test”)

In iOS 7 it returns file:// (so passing in “/var/test” would return “file:///var/test”)


UITableView Color Changes in iOS 7

Before iOS 7, the default background color for a UITableView was clearColor, and UITableViewCells by default took on the UITableView’s background color, so there was virtually no work setting up our tables in iOS 6.

When you switch to Xcode 5, your tables will default to the new iOS 7 behavior.  UITableView’s have a white background color by default, so you must change it to clearColor either in Interface Builder or programmatically.

More importantly, UITableViewCell’s no longer pick up the background color of the UITableView and are white by default. Setting the backgroundColor in InterfaceBuilder for a UITableViewCell has no effect (to my surprise I guess this has always been the case).

So, the “correct” way (based on Apple’s documentation in UITableViewCell) to set the UITableViewCell’s backgroundColor is to do it in the UITableViewDelegate willDisplayCell method, as shown here:


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    cell.backgroundColor = [UIColor clearColor];

Also, be sure your UITableViewCell’s contentView.backgroundColor is also set to clearColor (this can be done in Interface Builder).


I have found though that I can set the backgroundColor when I deque the cells in cellForRowAtIndexPath, but I’m not 100% sure this will work in all cases.



Nostalgia for the Amiga

I just finished reading the current set of articles on ARS Technica about the history of the Amiga computer (  It brought back great memories for me.  I was a Commodore fanatic from the time I got my Vic 20 at age 15, and the Amiga really was something unique and ahead of its time.  While I’ve long since lost my religious devotion to the Amiga, it still holds many fond memories for me, and was the foundation for my career in video software engineering.

While finishing my degree, I worked for Armadillo Brothers, a local computer chain that sold Amiga computers.  Many of the customers we sold to used the Amiga for video, and I ended up creating tools for them to do more with it.  One tool I created was a sing-along titler used by Living Scriptures for some of their animated videos (I didn’t have a good sense of the value of what I had created, and sold it to them for $30).  I loved creating software for the Amiga, it was so far ahead of its time in many of its operating system design concepts, and much of what I learned there has served me well in creating software throughout my career.

After college, my friend and colleague from Armadillo Brothers, Steve Gregerson, contacted me with his idea for Hollywood FX, so over 6 months in the basement of my first house, I created the software for Hollywood FX.  We released Hollywood FX a few months after Commodore went out of business, yet it still sold well enough to establish our business and become the foundation for the PC and Mac versions. It didn’t have any rendering code of its own.  It used AREXX to control Newtek’s Lightwave to render 3D transitions with multiple inputs.  AREXX also controlled separate frame store devices (ADPro and Video Toaster Flyer) to pull frames one at a time to use for texture mapping, and to write the resulting frames back out to the device.  A 1 second transition could easily take all day to render, but the quality was great, and it was a relatively inexpensive product for creating amazing 3D effects.

The Amiga version led to the creation of the Windows and Mac versions of Hollywood FX (which had their own OpenGL-based rendering engine), which led to Pinnacle’s purchase of Hollywood FX, and my 13 years at Pinnacle, Avid and Corel, where I’ve built and rebuilt FX and video editing technologies, worked with an amazing group of people, and led the development of Pinnacle Studio for iPad which I’m happy to be working on every day now as part of my new company, Luma Touch.


My Keys For Successful Scrum: The Story of Poe

One of my main reasons for starting this blog was to share some of the stories from the development of Avid Studio/Pinnacle Studio for iPad, codenamed Poe. It was the first development where we really used Scrum, and it ended up being a very successful product, and an incredible learning experience. There are a lot of stories and thoughts to share from this development.  In this blog entry I want to share what I think are some of the key elements to successful Scrum, many of which are ignored by other Scrum teams I’ve seen.


Early in 2011, after the release of Pinnacle Studio 14, the Pinnacle team at Avid went through a major upheaval (a nice way of saying 2/3 of the team was laid-off).  While that was an incredible blow to the team, it was also a chance to reorganize and try something new.  Toby Youngberg, the remaining engineer in my small office had just finished an iOS game on the side, and we discussed some ideas for video on the iPhone and iPad. This led to my proposal for a new video product on iOS, which would soon morph into Poe, a powerful video editor on the iPad.

For Poe, we were able to put together a small but really unique core team.  There were three full-time engineers: Toby Youngberg and myself in Salt Lake City and Oleg Tsaregorodtsev in Mountain View.  We also had Ray Johnson in Mountain View part-time, who helped with automation, localization, and so much more as usual). We had two QA engineers, Eddie Kestermont (who we nominated as ScrumMaster) and Eduardo Urrutia, and finally Terri Morgan in Seattle who was both product owner and designer (and had the distinct honor of having to prepare much of the material to satisfy the old product lifecycle process that Avid still held onto, hiding much of the tedious work from the rest of the team).

While this core team was responsible for the majority of the Poe product, it wouldn’t have been successful without a great deal of work from other teams and individuals.  These incredible people who all had a major role in Poe are listed in the Credits of Avid Studio and Pinnacle Studio for iPad.

So, with that basic background, here are the elements of Scrum that I think are most important based on our Poe experience.

1. Kick it off right

Getting a project started right can make a big difference in how it progresses.  The Poe team was lucky enough to come together for a full week of Scrum training with Bob Schatz of Agile Infusion (Avid had a clear mandate to move to Scrum for all development, and with a small remaining team, everyone was able to come together for this training).

This made a big difference in really understanding the foundation and details of Scrum. We had all thought we knew Scrum from previous projects, but we had only been following the basic mechanics, and were missing many of the key features that would bring us the most benefits (which is what this post is all about).

Even more important, on the last day of together, our team sat together in a room and kick-started the project from a Scrum standpoint.  We came up with a team name as well as amusing codenames for each member.  We developed the profile for our primary user, picked our ScrumMaster, and developed our initial backlog.

For our team’s mission statement, we wrote a loveletter to our users, telling them what it was we were trying to create and what we hoped they would get from it.

We created the rules for the team (if you were late or missed a stand-up more than once, you had to dance the Haka for all to see), and created our Definition of Done (see #6).

While we all knew each other well from years of working together, this was an important start to the project, where we all came together both physically and mentally.

By bringing your team together to kick-off a project, and making sure everyone is reasonably on the same page about the goals and rules of the project and team, things will run much more smoothly.

2. Pick the right ScrumMaster

I think a large part of the success of the Poe team was the choice of ScrumMaster: in our case, Eddie Kestermont.  The first time you meet Eddie, you’ll wonder what the hell you’ve gotten yourself into, but you’ll soon realize the intelligence, capability, and warmth behind the bold, big personality. He turned out to be the perfect choice for our team. He was strong enough not to be overriden by a very senior engineering team, and nice enough that when he told you to shut-up, you knew he meant it in the nicest way.  Eddie was also great at removing obstacles the team had in its way, which is a key responsibility for the ScrumMaster.  He also made retrospectives fun with trivia contests for prizes, and did a great job of facilitating planning meetings, stand-ups and retrospectives.

I recommend choosing a ScrumMaster who isn’t an engineer if possible.  In any case, pick someone who the team respects and who is dynamic and strong enough to stand up and remove obstacles both within and outside of the team.

3. Stand up in your stand-ups

I’ve seen so many stand-ups devolve into status meetings or technical discussions.  If your daily stand-ups our taking more than 10 minutes on average, then you either have too large of a team or you’re doing it wrong.  The first step to getting it right is to stand-up in your stand-ups. Many of us worked remotely, but we all stood up even on Skype, which felt a bit silly at first, but it made a difference.  It’s a reminder that you’re there to communicate what you’ve done, what you’re going to do next, and most importantly, are there any obstacles in your way.

Stand-ups will often lead to additional discussions after the stand-up or separate smaller meetings, but keep the stand-up simple, otherwise you’ll find yourself in daily hour-long meetings that you’ll quickly despise. Your ScrumMaster should be integral in keeping the stand-up on target, and in coordinating needed discussions.  You might get annoyed when he or she tells you to take the discussion offline, but you’ll appreciate it when you don’t have to lose time in endless discussions.

4. Communicate!

If you’re lucky enough to have a co-located team, you certainly have the best opportunity for success, but even in that case you need to work hard to make sure everyone communicates.  Often its a matter of personality.  Again, our ScrumMaster served an important role of drawing out quieter teammates to speak their mind.

If you’re geographically separated, make an extra effort to talk.  With Poe we really started using Skype to communicate regularly and less formally with separated teammates.  This face-to-face communication is critical, and much more effective than long email threads. We’d have design discussions where we would often draw something on paper and show it to others.  Remember though to follow-up a Skype discussion with a stored communication (email, Jira, Confluence/Sharepoint, Wiki) so that important decisions aren’t lost.

4. Break down your stories

I still see this as one of the biggest problems with Scrum teams.  I know that I personally had a tendency to  write what I thought was a pretty atomic story, only to realize that it could easily be broken down much further, and there was great advantage in iterative development to breaking it down that way.  For example, after the initial release of Poe, we finally got to Voiceover on our backlog.  Initially it was a single story, something like “As a documentary creator, I want to be able to add voiceovers to my video projects”.

After breaking it down, we had stories like:

  • As a user, I want a clearly understandable button to tap to bring up the UI for voiceover recording
  • As a user, I want a voiceover interface that shows which audio track I’ll be recording on.
  • As a user, I want the voiceover interface to default to the audio track with the most avialable time on it.
  • As a user, I want to be able to select any track to record a voiceover on.
  • Followed by another 20 stories that covered starting recoding, stopping recording, reviewing, keeping, canceling, etc.

When you’re in a sprint planning meeting, take the time to break down your stories to a point where each story is a manageable chunk of a couple of days work at most.  That should be further broken up into tasks that can each be completed in a few hours.  It’s an amazing benefit to productivity.  There were many times when I’d just finished a big story and wasn’t ready to take on a major piece of work.  I could just pick up a small story, maybe a UI element that needed to be added, and knock it off in 1/2 hour.  It would often kick me back into gear when I was drifting.

5. Don’t get locked into specific roles

Engineers on a team have a natural tendency to try tand divvy up stories and tasks at the beginning of a sprint based on their knowledge domains.  I strongly recommend avoiding this.  At least leave the option that different team members may take different roles during a sprint. With Poe, it was somewhat of an advantage that we were all fairly new to the platform, and even Toby who had the most experience still had a great deal to learn for the complexity of the product we were creating.

If your stories are broken up properly (#4), there is more of an opportunity for engineers to cross into new domains without it being too much of a burden on existing experts in that domain, and it will pay off in the long run.

6. Always follow your Definition of Done

Many Scrum teams don’t even have a definition of done, and for many that do, this is is the first thing to get lost, which was our problem with Poe.  The Definition-of-Done defines all the common elements required to consider a story or epic complete.  We had a good initial Definition of Done, including things like:

  • The product must build without any errors or warnings
  • All strings must be added for localization.
  • All automated tests must complete without failure.
  • All bugs reported by QA must be resolved.
  • Must have designer sign-off
Early on, we did well at this, making sure we checked off the Definition-of-Done items for every story, but after hitting a couple of roadblocks on the way that slowed down development, we started skipping some of these steps to try and get the product finished faster.  Within weeks we were seeing more crashes, more bugs that were propogating through the product, and it felt like we were moving towards disaster.  We ended up taking a sprint just to get back to a reasonable level of quality, and tried harder after that to stick to the Definition of Done.  Even after that, we weren’t careful enough to make sure every story really met our definition of done, and we paid the price, spending the first few months after shipping getting stability to a reasonable level.
This may be the hardest rule to follow, but it may be the most important.  You should set a clear Definition-of-Done up front for your project, and you shouldn’t consider a story complete until it’s met that defnition.  It’s much better to ship a high-quality product with features left on the backlog then spending time trying to recover stability in a large code base.

9. Sprint Reviews and Sprint Retrospectives

This is another area that I think many Scrum teams miss out on.  It’s something we did well with Poe, and it paid off. At the end of each sprint we would have a Sprint Review to demonstrate the completed stories from that sprint, and most importantly we would have a user demo to get feedback.  We brought in a variety of different types of users, including: professional editors, people from other divisions at Avid, even friends and family with a passing interesting in video.

Early on, it seemed like it would be silly, when all our app did was launch and display an image of the team, but we were always pleasantly surprised by the user feedback we would get that ultimately shaped a better product. New bugs would appear and things we didn’t notice were major blockers for users.  Try not to guide your users too much, instead give them a task to perform with the product, and let them try and figure out how to use it.  You’ll learn a lot watching a user struggle with something you thought was completely obvious. Don’t dismiss any feedback from your user demos.  Get everything into your backlog. Sometimes it’s the little things that will make the biggest difference.  Finally, reward the users who come in for a demo (in our case it was with a free Avid product, but it could be anything, including a $10 iTunes gift card).

After the Sprint Review, have a Sprint Retrospective with just your Scrum team.  This should be an opportunity to really look at what worked well and what didn’t from a Scrum-process perspective.  Were you overoptimistic about what was brought into the sprint, did you break up stories well, how was communication.  Did you really follow Definition-of-Done.  How did the demo go.  Are your stand-ups getting out of control.  Are there some things you can tweak to make it better.  Are there some major process-wide obstacles that need to be worked.  It’s here where you’re going to tweak and iterate the Scrum process itself to better meet your needs.

10. Don’t be afraid to iterate, which often means throwing hard work away

Scrum is all about iterative development.  Part of that is being willing to throw work away.  Early in the development of the storyboard/timeline concept for Poe, we realized that there were many things that just didn’t feel right about it.  We took one sprint to completely redesign the UX for the timeline.  After that rewrite, we did user reviews and found that our great new design was even worse.  So we threw that away, and wen’t back to a variation of the original design, but with numerous tweaks that came together to make it feel right. There were many other times during development where we went down a path only to find out that it didn’t pay off with the user like we thought it would.  Source control is your friend here.  We found ourselves cherry-picking from some of the dead-end paths we had gone down to more finely tune the final direction we chose.

This doesn’t mean just randomly picking a direction and heading there.  Your team should be making intelligent choices based on their experience, but it’s also easy to get locked into endless discussions about the “right” way to do something.  Sometimes you just need to pick one of the best choices and give it a try, with a willingness to drop it and start over if it doesn’t work.  If you keep things granular enough in your stories, then this usually means a few days work at most.  Hopefully going down that path also helps you learn something important about the right direction to head.

Bonus: Go around, climb-over, dig-under, blast a hole through

If there is one thing that resonated most in our training with Bob Schatz, it was this.  When you hit an obstacle, you need to find a way around it.  During the development of Poe, we ran into some major limitations of the iOS platform for video (which is amazingly powerful, but necessarily limited).  For example, one of the early obstacles was finding out that even though photos could be loaded as AVAssets, they couldn’t actually be used in a video composition.  So we quickly created a simple architecture that would render a photo into a small video clip that could be added to a composition (we realized later that this was exactly what iMovie was doing as well). Some of the obstacles we hit could have derailed the entire product, but we became master ninjas in finding ways to circumvent them.  Sometimes this meant redefining some feature, other times it meant finding some workaround that was “good enough” that would later be iterated into something more elegant.

Whenever you hit an obstacle, take a step back and figure out a way to get around it, over it, under it, or through it.  Talk to your team about the obstacle and listen to their ideas, particularly the non-engineers.  Often your first thought to an idea will be, that’s impossible!  But sometimes those impossible ideas will spark something that will end up being the perfect path.

Conclusion: Have Fun and Iterate Everything

Poe was an incredible experience, both in creating a product that I love, and in gaining a better understanding of the advantages of Scrum (as well as some of the pitfalls). It was also the most fun I’ve had engineering in a long time.

Remember that Scrum itself is something you need to iterate.  If you’re doing the same thing every sprint and every project, then you’re missing the point.  Scrum is a framework that you need to change and adapt constantly.  So keep iterating and have fun.


Adding Exception Breakpoints in XCode

I’ve been using XCode for over 2 years now, and had missed one important debugging feature (and my life has been more difficult for having missed it).

In the Breakpoints navigator, you can click on the + (add) button and select “Add Exception Breakpoint”. The dialog that appears will let you select specific breakpoints, classes of exceptions to break on, or let it break on all exceptions.

Without this I was guessing where the error occured. Luckily I was often correct, but what a waste of time.