Running Real Tests on watchOS

Since the first release of watchOS, it’s been a unique platform among Apple’s in that Xcode doesn’t support running unit test targets for it. This is of course a hindrance to writing maintainable code for the watch; with no tests, there’s a lot of manual testing involved. It’s hard to even debug some aspects of watch code—since the debugger requires the watch to be connected to the iPhone, which is in turn connected to the Mac via USB, you can’t debug a watch app’s behavior when it’s disconnected from the phone.

There have been efforts to allow limited testing of WatchKit code, but so far everything I’ve seen has one crucial flaw: the tests are actually running on iOS, either by testing a shared framework or by simulating WatchKit on iOS. This is all well and good, and certainly better than nothing, but it doesn’t allow you to test any platform-specific code. Inspired by other efforts to make cross-platform frameworks well-tested, I wondered what it would take to run actual tests on watchOS.

A Tale of Two XCTests

Much like PivotalCoreKit re-implements some of WatchKit to let an iOS target use it, my first thought was to re-implement some of XCTest to get existing test code to build under watchOS. As I dug through XCTest, however, I realized that it’s actually a pretty complex framework, and a complete reimplementation doesn’t make sense when Apple has already begun the task and has a perfectly good open-source repository just sitting there waiting to be used.

To use Apple’s XCTest reimplementation, I first had to create a podspec file to allow CocoaPods to set up my Xcode project. It looks like so:

Pod::Spec.new do |s|
  s.name         = "XCTest"
  s.version      = "3.0.1"
  s.summary      = "A watchOS compilation of Apple’s open-source XCTest."

  s.description  = <<-DESC
            A watchOS compilation of Apple’s open-source XCTest.
                   DESC

  s.homepage     = "https://github.com/apple/swift-corelibs-xctest"
  s.license      = "Apache License, Version 2.0"
  s.author    = "Apple"

  s.watchos.deployment_target = "3.0"

  s.source       = { :git => "https://github.com/apple/swift-corelibs-xctest.git", :tag => "swift-" + s.version.to_s + "-RELEASE" }

  s.source_files  = "Sources/**/*.swift"

  s.framework  = "Foundation"

  s.prepare_command = <<-CMD
                        find Sources/ -type f -name "*.swift" | xargs sed -e 's/import SwiftFoundation/import Foundation/g' -i ""
                        sed -i "" -e 's/usingBlock:/using:/' Sources/XCTest/Public/XCTestCase+Asynchronous.swift
                      CMD
end

While this is a fairly straightforward podspec, I did two interesting things in its prepare_command to get it to work:

  • Because the version I’m targeting uses the also-open-source SwiftFoundation instead of just Foundation, I use sed to change the import statement to point at regular Foundation. This has since been fixed, so this part will become unnecessary.
  • I used sed again to fix a method that had been renamed since this tag was created.

The prepare_command part of a podspec is often-overlooked as a way to fix up a pod without making a fork of your own to maintain.

Now that I had a version of XCTest that would build for watchOS, I set up a new target in my Xcode project called “WatchTests Test Runner WatchKit App” (with a corresponding WatchKit Extension target). This target does what it says on the tin: run it to run the tests. The Xcode project also has an iOS unit test target, and the goal is to share those tests with watchOS, so I simply linked the test files with the new WatchKit extension. When those files use import XCTest, they’ll be pulling from the Swift version automatically.

Running The Tests

To run the tests, you call XCTMain() with an array of XCTestCaseEntry objects that represent the test classes you’d like to test. As of right now, however, it’s still a goal of the Swift XCTest project to enable test method discovery without the Objective-C runtime, which means we need to do it. The easiest way is for each test class to implement a property called allTests, wherein you manually enumerate test methods. The final Swift test class might look something like this:

import XCTest

class WatchTestsTests: XCTestCase {
    
    #if os(watchOS)
    static var allTests = {
        return [
            ("testPassingTest", testPassingTest),
        ]
    }()
    #endif
    
    func testPassingTest() {
        XCTAssertTrue(true)
    }
    
}

This test can be compiled on iOS and watchOS. The extension delegate of the test runner WatchKit App then runs the tests:

import WatchKit
import XCTest

class ExtensionDelegate: NSObject, WKExtensionDelegate {

    func applicationDidFinishLaunching() {
        XCTMain([testCase(WatchTestsTests.allTests)])
    }
    
}

XCTMain will call exit with an exit status, so you can see the results in Xcode’s console:

Test Suite 'All tests' started at 22:36:14.852
Test Suite 'WatchTestsTestRunner WatchKit Extension.appex.xctest' started at 22:36:14.854
Test Suite 'WatchTestsTests' started at 22:36:14.854
Test Case 'WatchTestsTests.testPassingTest' started at 22:36:14.854
Test Case 'WatchTestsTests.testPassingTest' passed (0.001 seconds).
Test Suite 'WatchTestsTests' passed at 22:36:14.856
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'WatchTestsTestRunner WatchKit Extension.appex.xctest' passed at 22:36:14.856
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'All tests' passed at 22:36:14.856
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Program ended with exit code: 0

As you can see, this is exactly what you’d get out of XCTest on iOS, except it’s running in a watchOS target!

Limitations

This trivial example works well, but there are some limitations with this approach:

  • Because I’m using the Swift implementation of XCTest, the only existing tests that could possibly run are those written in Swift. You have to subclass XCTestCase to use XCTest, and you can’t make an Objective-C subclass of a Swift class, so for now at least, no Objective-C tests can run on watchOS. If Swift and Objective-C interoperability improves to the point where you can subclass a Swift class in Objective-C, look for this to improve. Alternatively, XCTestCase could be a protocol exposed to Objective-C, which would allow more flexibility in that regard.
  • Since we’re just running the tests directly, we don’t get any fancy Xcode integration. Failed tests won’t color a line red, nor will they run when you press ⌘U.
  • Our XCTestCase subclasses are in a unique position: they are subclasses of an Objective-C class on iOS, and subclasses of a Swift class on watchOS. This can confuse the compiler and leave you without code completion.

Nevertheless, I’m excited to start tinkering with tests on watchOS. I have a couple areas I’d like to explore:

  • Integrating these tests with CI of some sort. If I can get a shell script to return the watch target’s exit status, then I can get a Jenkins or Travis build to fail if the watch tests fail.
  • Testing the watch UI further. Right now the shared WKExtension’s rootInterfaceController property is nil during testing. Waiting for the UI to load before calling XCTMain() will probably help here.

I’d love to hear suggestions or feedback on this. The more tests are written for watchOS, the better and more maintainable our watch apps will be! If you want to poke around with my code, you can find it on GitHub.

Cocoa Touch: Working With Image Data

Images in Cocoa Touch, represented by the UIImage class, are a very important subject. Apple’s iOS platform prides itself on visual appeal, with Retina Displays, custom UI in many top apps, and a focus on photos with apps like Instagram. To that end, it behooves you as an iOS programmer to know a bit about working with images. This post won’t discuss everything you need to know about using the UIImage class, as that’s more appropriate for a book than a blog post—though maybe a series of blog posts would do—but instead will focus on one advanced topic: working with pixel data. You can find the basic stuff in the UIImage documentation, anyway.

Turning an Image Into Data

One of the first things you might want to do with a UIImage object is to save it to disk. To do that, you’ll need to save it to an image file. There are built-in functions to get properly-formatted data from an image, in both PNG and JPEG functions:

  • UIImagePNGRepresentation(), which returns an NSData object formatted as a PNG image, taking a pointer to a UIImage object as its sole parameter.
  • UIImageJPEGRepresentation(), which returns an NSData object formatted as a JPEG image. Like the previous function, its first parameter is a pointer to a UIImage object, but it has a second argument: a CGFloat value representing the compression quality to use, with 0.0 representing the lowest-quality, highest-compression JPEG image possible, and 1.0 representing the highest-quality, lowest-compression image possible.

Once you have the image data represented by an NSData object, you can then save it to disk with various NSData methods, such as -writeToFile:atomically:.

Getting Raw Pixel Data

While the above functions are great for saving images, they aren’t so great for image analysis. Sometimes you need to analyze the pixel data for a given pixel, down to the values for the red, green, blue, and alpha components. To get that kind of granularity in an image, we’ll be using a lot of CoreGraphics functions. If you haven’t used CoreGraphics before, know before going in that it’s a C-based API à la CoreFoundation, so you won’t be using the Objective-C objects you know and are used to. Instead, there are opaque types (represented by CFTypeRef, which is analogous to Objective-C’s id) representing objects grafted onto C, complete with manual memory management—no ARC for you. That’s neither here nor their, however; let’s talk about pixel data.

Color Space

The color space of an image defines what the color components of each pixel are. Represented by the CGColorSpace type, you’ll typically use either an RGB color space or a Gray color space, which have red, green, and blue components or a white component, respectively. For this example, we’ll be using the RGB color space. We can create an instance of it with the CGColorSpaceCreateDeviceRGB() function, which returns a CGColorSpaceRef type—think of it as a pointer to a CGColorSpace object.

What does using this color space get us? We now know that the pixels of our image will have three color components, and in what order. This will come in handy later on when we need to query the data.

Graphics Contexts

A graphics context, represented by the CGContext type, is analogous to a painter’s canvas—it’s what you draw into. For the purposes of drawing an image, you’ll create a CGBitmapContext, the ideal type of context for this data. You create a context with the CGBitmapContextCreate() function, which return a CGContextRef type. Let’s look at the declaration of that function (from CGBitmapContext.h):

CGContextRef CGBitmapContextCreate (
    void *data,
    size_t width,
    size_t height,
    size_t bitsPerComponent,
    size_t bytesPerRow,
    CGColorSpaceRef colorspace,
    CGBitmapInfo bitmapInfo
);

So, that’s pretty simple, right? It’s actually fairly straightforward, despite its appearance. Let’s break it down into more easily-digestible components. It’ll make more sense if we don’t go top-to-bottom, so we’ll go in the order I think makes the most sense.

First is the bitmapInfo parameter. The CGBitmapInfo type is a bitmask that represents two options: the alpha component, which contains transparency information, and the byte order of the data. We’ll talk about the alpha component here; byte order is another topic altogether. On iOS, only some pixel formats are supported. Looking at this chart in the documentation, we can see that, for all supported pixel formats on iOS in the RGB color space, these are the CGBitmapInfo constants we can use:

  • kCGImageAlphaNoneSkipFirst
  • kCGImageAlphaNoneSkipLast
  • kCGImageAlphaPremultipliedFirst
  • kCGImageAlphaPremultipliedLast

We can do two things with the alpha component: skip it, or use it in a premultiplied format. The premultiplied flag tells the system to multiply the individual red, green, and blue components by the alpha value when storing it. So, instead of RGBA values of 1, 1, 1, and 0.5, it’s stored as 0.5, 0.5, 0.5, and 0.5. This is a performance-saving measure on iOS devices, and is done automatically to all of your PNG images by Xcode when you build for a device.

So, for the bitmapInfo parameter, I generally pass kCGImageAlphaPremultipliedLast.

The penultimate parameter, colorspace, is a CGColorSpaceRef pointing to a color space you’ve created. This informs the context about the number of color components. Keep in mind that there’s one extra component for the alpha information if you’re not skipping it, so an RGB color space uses 4 components including alpha.

The width and height parameters are pretty simple: the number of pixels wide and high to make the context. Keep in mind that for Retina displays, you may need to double the values. You can use the scale property of the main UIScreen object as a quick “am I on a Retina device?” check.

Next, let’s talk about the first parameter: data Here you have two options: to pass in a pointer to a region of memory you’ve allocated for the image data, or to pass NULL and have the graphics subsystem create it for you. If you’re trying to access pixel data, however, it’ll help to have a pointer to the data, so here you’d pass in memory you’ve allocated. How do you know how much is enough? Let’s look at the bitsPerComponent parameter. I usually use 8-bit components—again, see the chart linked above for valid options—so I would pass 8 for bitsPerComponent. Once you know that, you can determine bytesPerRow easily:

size_t bytesPerRow = (bitsPerComponent * width) / 8;

And then, finally, we can determine how much data to use. I use the uint8_t data type to represent this, as it’s an unsigned 8-bit integer, perfect for our needs.

uint8_t data = calloc((width * height) * numberOfComponents, sizeof(uint8_t));

The entire stack might look like this:

The only thing in this code that we haven’t gone over so far is the call to CGContextDrawImage, which (surprisingly) draws the image. It takes three parameters: the context to draw into, a CGRect defining where to draw, and a CGImageRef for the image. You can obtain a CGImageRef from a UIImage using its -CGImage method.

Now that the image is drawn in our context, the rawData array will be filled with real, live image data! You can access it like so (modify the values of x and y as suits your needs):

int x = 0;
int y = 0;

int byteIndex = (bytesPerRow * y) + (x * bytesPerPixel);

uint8_ t red   = rawData[byteIndex];
uint8_ t green = rawData[byteIndex + 1];
uint8_ t blue  = rawData[byteIndex + 2];
uint8_ t alpha = rawData[byteIndex + 3];

And there you have it! Now that you’ve gotten the data out of your image, do whatever you want with it. Just remember the blog authors you read along the way when Facebook buys you for a billion dollars.

Note: The venerable Mike Ash published a similar article while this one was half-done in my drafts folder. I thought about scrapping it altogether, but since mine is iOS-specific, and with some prodding from a co-worker, I decided to press on. Go read Mike’s blog, too. It’s awesome.

Enforcing iOS Security Settings in Third-Party Applications

A while back, I was working on an  application for a client with a very specific requirement. Since it collected personal data, the application could only run on iOS devices that were protected with a passcode. This requirement, seemingly very simple from the client’s perspective, was a bit of a hassle to implement on the programming side of things. There’s no simple method on UIDevice to determine if a passcode is set, nor is there a way to force that programatically. In fact, there’s no way to force most things like that. The iOS device isn’t the programmer’s, it’s the user’s. Except when it isn’t.

One of the things that you can do is to use the iPhone Configuration Utility to make a configuration profile. These profiles can support a range of things, from requiring a passcode (or even an advanced, non-numeric passcode) to WiFi settings, VPN to CardDAV settings. Creating a configuration profile that requires a passcode, then installing that configuration profile onto the device is a no-brainer. But how do you ensure that the application will only run in that case?

Disclaimer: Before I go any further, you should know that since this was an in-house project, none of the code that I wrote made it into the App Store. Therefore, I don’t know if this is kosher in an App Store app, nor do I recommend this approach for that.

One thing that you can do is to include a self-signed certificate in a configuration profile. Those of you familiar with OpenSSL may be groaning as you realize where this horrible, horrible workaround is headed. I created a new certificate authority. With that new certificate authority, I signed a separate certificate that I had created. Verifying this certificate, then, requires that the verifying party accept the certificate authority’s certificate as valid. Well, since you can set that in the configuration profile, I did, along with the passcode requirement. Then, in the app, I bundled the certificate that I had signed with my CA.

When the app starts up, it attempts to verify the certificate. In the case where the configuration profile is installed and the CA’s certificate is in the system’s keychain as trusted, this is no problem: the certificate checks out and my app is free to go. If that validation fails, however, then I know that the certificate from the CA is in the system, so I know that the configuration profile is installed, as well.

Why this works for a passcode so well is that to install a configuration profile on a device without a passcode when the profile requires one is that you can’t install it without setting a passcode in the process. For the client, this was Good Enough, and the app shipped and worked properly. It’s worth noting, though, that the less the end-user knows about this process, the better. To circumvent the passcode restriction, all one would have to do would be to modify the configuration profile to still include the CA’s certificate, but not the pas code requirement. For that reason I can’t recommend this for anything like EMR or tax records, but for minor demographic information like we were collecting, this sufficed.

I realize this didn’t include any code, but the individual portions aren’t that hard, and I don’t have access to the original code so I’d have to re-write them all. Here they are in a nicely-formatted list for those keeping score at home:

  1. Create a new certificate authority with OpenSSL.
  2. Create a new certificate, then sign it with that certificate authority you just created.
  3. Create a configuration profile in the iTunes Configuration Utility with the settings you would like to enforce.
  4. In the “Credentials” section in the iTunes Configuration Utility, add your CA’s public-facing certificate to the configuration profile.
  5. Add the certificate you signed with your CA to your application’s bundle.
  6. In your application, verify the certificate you included.
  7. Distribute the configuration profile along with your application to end users.

Like I said, this is far from perfect. But when you’re working with an enterprise client who has Big Needs, this is one trick to keep in your back pocket when you’re up against a deadline.

Cocoa Touch: Circumventing UITableViewCell Redraw Issues with Multithreading

In your career as a Cocoa or Cocoa Touch developer, every now and then you’ll encounter an issue with something Apple has written. Whether it’s a full-blown bug, something that doesn’t work quite how you’d expect it to, or a minor inconvenience, it happens. When it does, naturally the first thing you do is file a bug report (right?). After that, though, you need to do something about it. This usually occurs right when a project is due, so often we can’t wait for Apple’s engineering teams to fix the problems (or tell you that you’re wrong). This post is an example of using KVO to get around the problem without worrying about it anymore.

The Problem: In iOS, if you create a UITableViewCell and return it to the table view in its data source’s -tableView:cellForRowAtIndexPath: method, but then return later (say, after doing some background processing) to add an image to the cell’s imageView, you don’t see anything! Why? Well, it looks like either the image view isn’t added to the cell’s view hierarchy if you don’t immediately add an image or there’s some other bug in the UITableViewCell implementation. I don’t think it’s a bug, I think it’s just a side effect of an optimization; if there’s no image, why add it to the cell?

So how do we fix it? Well, a simple call to -setNeedsLayout gets the cell to fix itself quite nicely. But we shouldn’t have to do that from our table view data source—that has a bit of code smell to it. Lines like that quickly get overused, with programmers calmly stating, “I don’t know why, but we always do that.” No, a better solution is to get the cell to handle this problem on its own.

We’ll create a subclass of UITableViewCell and use KVO. When we create the cell, we’ll register for KVO notifications with the on the image view whenever its image property is modified—but we’ll send the option to include the old value in the change dictionary. When we receive the notification, we’ll look at that dictionary, and if the old value was nil, then we’ll send self a -setNeedsLayout message. This avoids having to do it in other classes, and only does it when necessary. We simply set it and forget it.

Ta-da.

GCD Example Updated (Now With More Speed!)

Due to popular demand, I’ve updated my GCD example from previous talks to include a few things to make the example not only do something on a background queue, but also snappy. It should scroll much better now. A quick rundown of what changed:

  • Images are now resized. Since the example uses wallpaper-sized images, there’s no sense in not resizing them to go on a 44-pixel-tall table view cell. I’m using the popular image-resizing routines from Trevor’s Bike Shed to do the resizing with a nice interpolation quailty.
  • Those resized images are now cached. I use an NSCache to store the images. If the app receives a memory warning, it’ll jettison all of the cached images, but if you’re just scrolling up and down this is a quick and dirty way to cache the images. I had never really used NSCache before, so this was a good excuse to try it.
  • I’m at CocoaConf in that state down to the South today, so this post has been brought to you by late-night hotel room caffeine. I made some other changes to the project to deal with a weird table view cell bug that I’ve submitted to Apple; a post on that is coming up next!