Sunday, 28 February 2016

Simulating signals in Swift, part 2: Mocking the accelerometer on the iOS Simulator

TL;DR - Mock the accelerometer in the iOS simulator using "Runner"
Following from part 1 where I described how I implemented Runner I'll give some examples of how it can be used to mock the accelerometer in the iOS simulator. These examples can be found in the example app from the Github repository.

CMDeviceMotion setup for mocking

Motionable protocol needs to be declared so that the points being fired have userAccelerationgravity and rotationRate.
protocol Motionable {
  var rotationRate: CMRotationRate { get }
  var gravity: CMAcceleration { get }
  var userAcceleration: CMAcceleration { get }
}

extension Motionable {
  var rotationRate: CMRotationRate { return CMRotationRate() }
  var gravity: CMAcceleration { return CMAcceleration() }
  var userAcceleration: CMAcceleration { return CMAcceleration() }
}
The Motionable protocol is used to replace the CMDeviceMotionHandler from the CMMotionManager class:
public typealias CMDeviceMotionHandler = (CMDeviceMotion?, NSError?) -> Void
This way a Motionable type instead of CMDeviceMotion object is returned:
typealias MotionableHandler = (Motionable, NSError?) -> Void
This means that CMDeviceMotion needs to conform to this protocol for the new completion handler to work:
extension CMDeviceMotion : Motionable {}
The first step is to create a class that will be used to interact with the CMMotionManager. This keeps the CoreMotion framework's boilerplate code on one class that can be reused in multiple places of an app.
private let defaultDeviceMotionUpdateInterval = 0.01

class DeviceMotionWrapper {
  
  private var motionManager : CMMotionManager = {
    let motionManager = CMMotionManager()
    motionManager.deviceMotionUpdateInterval = defaultDeviceMotionUpdateInterval
    return motionManager
  }()
  
  private var queue : NSOperationQueue = {
    let queue = NSOperationQueue()
    queue.maxConcurrentOperationCount = 1
    return queue
  }()

}
Up until this point the accelerometer would only log changes when run from a physical device since the iOS simulator does not have a built in accelerometer. Hence, the DeviceMotionWrapper class needs to be extended to use Runner to execute accelerometer points in case the iOS simulator is being used. 
A property storing an instance of Runner needs to be added to the DeviceMotionWrapper class:
private let runner = Runner()
...and a function to start the real accelerometer using the new MotionableHandler completion:
func startRealDeviceMotionUpdates(handler: MotionableHandler) {
  motionManager.startDeviceMotionUpdatesToQueue(queue) {(deviceMotion, error) -> Void in
    
    guard let deviceMotion = deviceMotion else {
      return
    }
    handler(deviceMotion, error)
  }
}
Finally, I defined a struct for the MotionablePoint I was going to mock that conformed to Motionable and Runnable. For this example I only mocked the userAcceleration but gravity and rotationRate can also be added.
struct MotionablePoint : Runnable, Motionable {
  let timestamp : NSTimeInterval
  let userAcceleration : CMAcceleration
}

Case 1: Using an array of predefined points to execute

To be able to fire a predefined set of points in case the accelerometer is not there, a new generic functions needs to be added to the DeviceMotionWrapper class. It takes an array of both Motionable and Runnable points and either it executes these points on the iOS simulator or ignores them and defaults to the accelerometer. The #ifdef is used to only mock the accelerometer when the iOS simulator is running. An alternative would be to check whether the deviceMotionAvailable is available from the CMMotionManager instance.
func startDeviceMotionUpdates<PointType : protocol<Runnable, Motionable>>(mockPoints: [PointType]? = nil, timeInterval: Double = defaultDeviceMotionUpdateInterval, handler: MotionableHandler) {
  
  #if (arch(i386) || arch(x86_64)) && os(iOS)
    if let mockPoints = mockPoints {
      startMockedDeviceMotionUpdates(mockPoints, handler: handler)
      return
    }
  #endif
  
  motionManager.deviceMotionUpdateInterval = timeInterval
  startRealDeviceMotionUpdates(handler)
  
}

private func startMockedDeviceMotionUpdates<PointType : protocol<Runnable, Motionable>>(mockPoints: [PointType], handler: MotionableHandler) {
  
  runner.startWithMockPoints(mockPoints) { (mockPoint) -> Void in
    handler(mockPoint, nil)
  }
  
}
This would be used like this:
var mockPoints = [MotionablePoint]()

for index in 0...100 {
  let value = Double(index)
  let userAcceleration = CMAcceleration(x: value, y: value, z: value)
  let mockPoint = MotionablePoint(timestamp: NSTimeInterval(index) / 10, userAcceleration: userAcceleration)
  mockPoints.append(mockPoint)
}

deviceMotionWrapper.startDeviceMotionUpdates(mockPoints) { (point, error) -> Void in
  NSLog("\(point)")
}
When running this on the simulator the points will be the ones from the for loop and when running on the device the points will be the once from the device accelerometer.

Case 2: Using a function to mock the acceleration

Similarly from the previous example a new function on DeviceMotionWrapper is declared to mock the accelerometer using a signal function. In this case the first argument is a function that uses a generic type for the point to run since this point needs to conform to Motionable and Runnable.
func startDeviceMotionUpdates<PointType : protocol<Runnable, Motionable>>(signalFunction: (NSTimeInterval -> PointType)? = nil, timeInterval: Double = defaultDeviceMotionUpdateInterval, handler: MotionableHandler) {
  
  #if (arch(i386) || arch(x86_64)) && os(iOS)
    if let signalFunction = signalFunction {
      startMockedDeviceMotionUpdates(signalFunction, timeInterval: timeInterval, handler: handler)
      return
    }
  #endif
  
  motionManager.deviceMotionUpdateInterval = timeInterval
  startRealDeviceMotionUpdates(handler)
  
}

private func startMockedDeviceMotionUpdates<PointType : protocol<Runnable, Motionable>>(signalFunction: (NSTimeInterval -> PointType),  timeInterval: Double = defaultDeviceMotionUpdateInterval, handler: MotionableHandler) {
  
  runner.startWithFunction(signalFunction, timeInterval: timeInterval) { (mockPoint) -> Void in
    handler(mockPoint, nil)
  }
  
}
Similarly as in the previous example, this would be used like this:
deviceMotionWrapper.startDeviceMotionUpdates(sineSignal, timeInterval: 0.1) { (point, error) -> Void in
  NSLog("\(point.userAcceleration)")
}
The sine signal function as explained in the previous post is defined as:
// A.sin(f.t+phaseShift)+offset
func sineSignal(nextTimestamp: NSTimeInterval) -> MotionablePoint {
  let signalFrequency = 1.0
  let amplitude = 2.0
  let offset = 0.5
  let phaseShift = 0.2
  let value = amplitude * sin(nextTimestamp * signalFrequency + phaseShift) + offset
  let userAcceleration = CMAcceleration(x: value, y: value, z: value)
  return MotionablePoint(timestamp: nextTimestamp, userAcceleration: userAcceleration)
}
It may be clearer to download and have a look at all the code together to understand the whole implementation. This can be found on Github.

Sunday, 21 February 2016

From Objective-C to Swift: Approaches to decoding JSON

As developers, we must solve real world problems by using programming languages that impose on us various constraints. An algorithm therefore, might vary significantly depending on the characteristics of the implementation language. It's therefore important to think about how best to utilise the language features when reasoning about problems.
As an iOS developer, I've been affected by Apple's introduction of Swift. Swift's characteristics differ significantly from those of its predecessor, Objective-C. While it's usually possible to write Swift like objective-C' by making use of Objective-C's runtime, this doesn't mean that doing so provides the best approach. It's therefore important to think about how the problem can be solved in a 'Swifty' way. We can briefly summarise some of the differences between the languages:
  • - Objective-C dynamicness vs Swift's strongly-typed system
  • - Introspection is more extensive in Objective-C
  • - Swift has generics
  • - Objective-C allows sending messages to nil
  • - Swift's built-in vTable vs Objective-C's messages for method dispatch
To illustrate how the differences between these languages can affect the solution to the problem, we're going to look at a common task that exists on many iOS apps: mapping a JSON dictionary into a model object.
This is our very simple, example JSON file:
{
    "name" : "John Doe",
    "company" : "Doe Industries plc",
    "email" : "john@doeind.com",
    "partTime" : true
}
Our simple task is therefore to map this JSON file into an Address model object.
When approaching the problem as Objective-C developers, we might think that one good approach is to loop through the keys of the JSON dictionary, check if the model object has properties matching those keys and if so assign the appropiate value. We can implement this making use of Objective-C's powerful introspection:
Our Address class in Objective-C:
@interface Address : NSObject

@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *company;
@property (copy, nonatomic) NSString *email;
@property (strong, nonatomic) NSNumber *partTime;

@end
Address *newObject = [[Address alloc] init];
    
NSString *jsonFilePath =
[[NSBundle mainBundle] pathForResource:@"address" ofType:@"json"];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:jsonFilePath];
    
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    
[json enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
        
    SEL selector = NSSelectorFromString(key);
    if ([newObject respondsToSelector:selector]) {
        [newObject setValue:value
                     forKey:key];
    }
}];
We could use the respondsToSelector: in Swift, however our object would have to inherit from NSObject and we would end up using the Objective-C runtime. This will not be possible if our model classes are Structs, or the properties are optionals for example. The same applies to the setValue:forKey: method as well as NSSelectorFromString().
We don't want to write Swift code as if it was Objective-C, constantly making use of the Objective-C runtime to achieve our goals. Nor do we want to avoid declaring our model objects as Structs. Even if we're happy to depend upon the Objective-C runtime, we wouldn't be able to declare the model object properties as let because we wouldn't be able to use setValue:forKey: with them. We therefore need to think about the problem differently, starting by the fact that Swift is a strongly-typed language in which methods are called not by method-dispatch at runtime, but by using a vTable.
While Swift has some introspection through the Mirror object, it's not enough to follow the same procedure, as we can't check if an object implements a certain method. In our example, we would need to know if the key of the parsed dictionary, has a corresponding property of the right type.
It's quite clear that it won't be possible to iterate through a dictionary of [String: AnyObject] and assign each key to an object property in Swift. We will need to actually list the keys we wish to map manually. This is not as bad as it sounds, given that we benefit from Swift's strong-type checks, reducing the likelihood of errors.
A simple Swift version could be:
struct Address {
    
    let name: String?
    let company: String?
    let email: String?
    let partTime: Bool?
    
    init(dict: [String: AnyObject]) {
        
        name = dict["name"] as? String
        company = dict["company"] as? String
        email = dict["email"] as? String
        partTime = dict["partTime"] as? Bool
    }
}
let path = NSBundle.mainBundle().pathForResource("address", ofType: "json")
let jsonData = NSData(contentsOfFile: path!)

do {
if let jsonDic = try NSJSONSerialization.JSONObjectWithData(jsonData!,
    options: .MutableContainers) as? [String: AnyObject] {
    
    let addr = Address(dict: jsonDic)
    // do something with your addr object
}
    
} catch {
    
}
Now that's an awful lot of casting, which is not only a pain to write but it also requires us to specify the right type otherwise the cast will fail and the property will be nil.
We can do better by using Swift's powerful Generics:
public func decode<T>(dictionary: [String: AnyObject], key: String) -> T? {
    return dictionary[key] as? T
}

struct Address {
    
    let name: String?
    let company: String?
    let email: String?
    let partTime: Bool?
    
    init(dict: [String: AnyObject]) {
        
        name = decode(dict, key: "name")
        company = decode(dict, key: "company")
        email = decode(dict, key: "email")
        partTime = decode(dict, key: "partTime")
    }
}
That's a significant improvement from having to type-cast every property. Naturally, it would be necessary to provide a decode function for non-optional types and for arrays to support embedded JSON objects.
If you're interested in learning more about this approach, have a look at Luciano's open-source JSON mapper called JSONUtilities. If you're interested in learning more about the Objective-C approach, you can have a look at my mapper TBRJSONMapper which is fully compatible with Swift and does not require you to write dictionary keys in your code.

Conclusion

In this post we've seen how the language features condition our approach to solving problems. We've looked at the problem of mapping a JSON file to a model object. Objective-C's dynamicness and introspection allows us to loop through the keys of the parsed dictionary and set the appropriate value into our model object if it implements the property for that key. This approach does not work in pure Swift (without using the Objective-C runtime), so instead we made use of Generics to map a dictionary entry into a model object property. The Swift approach requires us to specify the dictionary key in codes but we end up with a more robust, type-safe implementation.