Nim on iOS

The Nim programming language is simple, clean language with a style that will be familiar to Python programmers, but has the performance benefit of compiling down to C. The C the compiler generates is different depending on whether you have 32-bit or 64-bit code, which makes compiling for iOS (which has to target both 32-bit and 64-bit) awkward.

In this blog post I'll summarise how you can use Nim for components of your app. I've got a working version of this project available on GitHub.

Firstly, if you haven't already, grab the compiler and compile it (don't worry, this is easy). Then create a new Objective-C project in Xcode. I've called mine nim-ios-demo:

Next you'll want to create two directories: scripts and src. Your folder structure should look like this:

The src folder is where you'll be placing your Nim source files. In scripts you need to place my xcode_prebuild.sh script (I modified it from work by Grzegorz Hankiewicz). This script compiles the Nim source files to C and creates the merged 32-bit/64-bit files. You need to add this script as a build phase in Xcode:

There are two minor changes that you'll need to make to the script to use it in your project:

  • Set the PROJECT_DIR variable
  • Set the PATH_TO_NIM variable

Add your Nim source files in the 'src' directory. In this example I'm going to use a very simple function:

# Saved as backend.nim in the src directory
proc hello*(name: cstring): cstring {.exportc.} =
    result = "Hello " & $name

You can optionally add this to your Xcode project, but make sure that you don't have Xcode set to copy or compile it! Note that we need the asterisk after the function name so that it gets exported, and {.exportc.} ensures that the name doesn't get mangled. We also have to use cstring rather than string (Nim's native string type) but they get bridged automatically at no cost.

Build your project. This will run the Nim compiler and generate the C files you need to include in Xcode. Go ahead and add the contents of src/build/nimcache to your project:

If you build now you'll get a lot of warnings (50+). If you want to avoid these, add the -w flag to the files in their compile stage:

Before you can use the Nim function you'll need to configure the Garbage Collector. Add the call to NimMain in main.m:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "backend.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        NimMain();
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

For my example, I've created a simple app that echoes the user's name. To call the function, you'll need to import backend.h:

#import "ViewController.h"
#import "backend.h"

@interface ViewController ()
- (IBAction)textChanged:(UITextField *)sender;
@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation ViewController

- (IBAction)textChanged:(UITextField *)sender {
    char * helloName = hello((char*)sender.text.UTF8String);
    self.label.text = [NSString stringWithUTF8String:helloName];
}

@end

By using [NSString stringWithUTF8String:] we can copy the contents of the string, which ensures that when Nim cleans up the memory later (helloName) we don't lose the string.

Finally, you can build and run the app:

Once you're up and running it is trivial to add new Nim code to your project. So far I've been very impressed with the language, and I may even use it in the future in my apps.

Programming Language of the Month

When Apple announced Swift last summer I was excited to learn a new programming language. After having programmed almost exclusively in Objective-C (with a bit of Go, JavaScript, C#, Java, and C++ on the side) for two years I thoroughly enjoyed picking up Swift's new concepts* such as functional programming, generics and values.

Having enjoyed my experiences with Swift, I decided to play with a new programming language each month, so since July 2014 I've had a Programming Language of the Month:

The amount of work I've done in each language has varied hugely. I only did a small amount of work in Prolog to familiarise myself with the basic concepts, but I've written semi-large programs in all of the others.

Learning, or at least experimenting with, a new language is a tremendous adventure for any programmer. Its been a valuable experience picking up ideas in a variety of functional, imperative and declarative programming languages. If you've got the time, I'd give a PLoTM a try.

*As in new to iOS/OS X platforms.

Cake Day 2

Cake Day, my iOS app that reminds you once a year of your reddit cake day (birthday), has been updated with a new UI and iPad support.

Changes:

  • Completely removed the hamburger menu. Apple discourages these and it didn't work brilliantly, so I decided it would be best if it went
  • Changed the app's default font (now using Open Sans)
  • Rewrite of the app in Swift. I hadn't originally planned to do this as part of the update, but I wanted to see whether or not Swift could improve my programmer productivity. Overall I found that the amount of code that I had to write was similar - although I now have a lot more database could for dealing with SQlite.swift than I had before when using FMDB
  • The app is now open source you can contribute or post issues at GitHub

You can download Cake Day for free from the App Store.

Keep Calm 4.1 with PDF export

I've published an update to Keep Calm for iOS just in time for Christmas. This version adds PDF export for Pro users, which is great if you want to print your posters from your computer later. PDFs can be either opened in another app (Kindle, iBooks, Dropbox, etc) or shared directly (email, iMessage).

You can download Keep Calm for free from the App Store. The Pro upgrade costs $0.99.

OpenGL.swift

It is a little bit of a pain to use OpenGL with Swift as GLKit is barely compatible. This is because GLKit's math functions and types are all based off of unions, which Swift doesn't support because they are designed to be unsafe. You are left with two choices: roll your own matrix library in Swift (which may miss out on the ARM NEON or Intel SSE performance enhancements) or hide GLKit behind some Objective-C.

I decided to go for the latter, and the product is OpenGL.swift. Instead of using unions I have used structs which contain one member:

typedef struct {
    GLfloat m[16];
} TDMatrix4;

I then wrapped all of GLKit's math functions and I internally cast my matrix and vector types to the GLKit types in Objective-C code. As all of my functions and all of the GLKit functions get inlined there is no performance cost to this. My code was all generated by a Ruby script directly from the GLKit headers.

Once I had wrapped all of the GLKit math functions and types I then wrapped all of the uses of matrices and vectors in GLKit classes, so you can actually use them from Swift:

let aspect = GLfloat(CGRectGetWidth(self.view.bounds) / CGRectGetHeight(self.view.bounds))
let projectionMatrix = TDMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0)
self.effect?.transform.td_projectionMatrix = projectionMatrix

At this point I then added operator overloading using all of the standard methods, so in Swift you can concisely do matrix math:

let mvpMatrix = projectionMatrix * modelViewMatrix

As well as this I also added wrappers around the standard uniform functions so it is much simpler to submit matrix and vertex data to the GPU:

//Submitting vertex data
glBufferData(GLenum(GL_ARRAY_BUFFER), vertexData, GLenum(GL_STATIC_DRAW))
//Setting uniform data
glUniformMatrix4fx(mvpMatrixSlot, TDFalse, mvpMatrix)

You can get the source for OpenGL.swift on GitHub (there are instructions for dropping it into your project there as well).

Linking GLKit and Objective-C++ in Xcode 6

If you create a new Objective-C GLKit project in Xcode 6 and rename your main view controller to a .mm (Objective-C++) file you'll immediately get linker errors with some of the common GLKit classes not being found. This is because in Xcode 6 you don't have to explicitly link against Apple frameworks. To fix the linker errors, just add GLKit.framework to your Linked Frameworks and Libraries.

Building Keep Calm 4

A couple of days ago I released Keep Calm 4 for iOS, just over two years after the release of the first version. The new update brings several bug fixes as well as a few new niceties. Despite the bump in the version number this has probably been one of the smallest updates I've done to the app since its release. In this post I'm going to give a technical overview of some of the work I've done on the app.

View controller transitions

In iOS 7 Apple introduced View Controller transitions (see objc.io for a really good tutorial). These give you full control over how one view controller transitions to another. In the above video you can see that I am pushing from a UICollectionViewController to a custom view controller (alternatively I could have used a Collection View layout transition, but this would have been a bit inefficient for my use case). Towards the end of the video I swipe in from the left of the screen (i.e. the standard back gesture) and you can see that the poster interactively shrinks back into its original position. In order to achieve the effect I do the following:

  1. Set the navigationController delegate to the UICollectionViewController
  2. The UINavigationControllerDelegate methods return instances of KCCInteractiveTransiton, which handle the back and forward transitions. KCCInteractiveTransition is a subclass of UIPercentDrivenInteractiveTransition and implements UIViewControllerAnimatedTransitioning
  3. All of the collection view cells undergo an animation that shrinks them (sets their transform to a scale of 0.75) and fades them out
  4. The new view controller is immediately added to the view, along with the main poster view
  5. The poster view is positioned in the same place as the cell that was tapped
  6. The poster view then undergoes an animation that causes it to fill the screen

In reverse a similar series of events happens, except that it also supports interaction (so you can effectively watch the animation in slow motion). I've also used some of the spring based animations in iOS 7 to give it a little bouncing effect. The following values produce a fairly subtle bounce:

[UIView animateWithDuration:0.5f delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    ...
}];

It wasn't particularly trivial to implement the interactive transition, and it was made harder by the fact that I'm using Auto Layout pretty much everywhere in Keep Calm now. Auto Layout animations also work slightly differently to regular animations as well, because you don't set the final state of the animation inside the animation block:

//Configure contraints for 'final' animation state
[UIView animateWithDuration:duration animations^{
    //'Apply' the updated constraints
    [self.view layoutIfNeeded];
}];

Vector crowns

Keep Calm contains 1000 custom crowns that you can replace the crown at the top of the poster with (as well as the option for images and emoji). In previous versions these have always been @2x PNG files and they took up about 70% of the app's bundle size. This has been fine up until now, but with the @3x iPhone 6+ I really needed to improve the quality.

Now Keep Calm ships mostly with PNGs still but many of the more common crowns have been replaced with vector paths instead. These vectors have been produced by:

  1. Taking the original SVG file and simplifying it down to one path using Sketch
  2. Converting strokes to filled paths
  3. Exporting each crown as an SVG file
  4. Running a custom C program on each SVG file to produce binary encoded path data, which is then stored in an SQLite database
  5. Keep Calm loads the binary path data from SQLite and decodes it using a custom UIBezierPath extension
  6. Paths are rendered in a custom view using the appropriate color

As the binary encoded path data is fairly efficient the app's bundle size will slowly decrease as I convert more crowns to the new format, but more importantly the quality of the rendered crowns on screen will vastly improve.

Core Image colorization

As well as being able to change the crown in Keep Calm, you can also change the color of it. In older versions of the app the white crown PNGs were filtered using a CIColorMatrix filter. Unfortunately, despite having the math right, the produced color was always slightly different from the text. It was usually fine for gray scale colors, but anything else would be off by ±5%. I'm still yet to establish why this occurred, but there was an easy work around.

I now create a plain CIImage which represents a single color. Then I apply a mask to that image using the alpha channel of the crown image. The result is a correctly colored crown image.

This bug has been in Keep Calm for nearly two years, so I'm delighted to finally fix it once and for all.

Supporting iOS 7 and 8

Keep Calm 4.x will continue to support iOS 7 into the foreseeable future. I'm not depending on any iOS 8 features like extensions, so it makes sense to support iOS 7 still. Furthermore, given that iOS 8 adoption is slower than iOS 7 it will be a while until the majority of my customers are on iOS 8. A key factor I have to consider is that the vast majority of Keep Calm users tend to be children, so devices like the iPod touch and 16GB iPhones make up the majority of my users. These devices may not have been updated to iOS 8 in fears that it will slow them down or that it requires too much free storage space.

Swift

This update doesn't contain any Swift because it was primarily written against the iOS 7 SDK in about July (I was slow releasing it because of the extra work of vectorizing crowns). I'm pretty sure that I will begin to use Swift more over the next few months, but for now I'm restricting it to where I'm creating new classes.

Future

Keep Calm on iOS remains a priority for me over the Android version. Over the next few months I'll be adding more vector crowns and bug fixes. The next update (probably 4.1) will likely be a 'Snow Leopard' style release where changes are primarily just fixes and minor improvements rather than major new features.

About half of all of the code in Keep Calm is in my private shared framework that I use across my apps. I've finally begun cleaning it all up and putting it in separate modules, so it is actually reasonably likely that it will be fully open sourced in the next few months :).

Material Design PDF icons

Today Google released a bunch of their Material Design style icons on GitHub. Unfortunately for iOS developers they only included @1x, @2x and @3x PNG icons (as well as the raw SVG vectors). I've therefore used a couple of shell scripts to generate PDFs that can be used in Xcode 6 Image Catalogs (where Xcode 6 automatically generates the PNGs for you, which saves a lot of time). You can download my PDF icons by downloading the 'icons_pdf.zip' file from this repository.