Habits 3.0.1

Just in time for the New Year, I released a new version of Habits

  • Habit names are multi-line on the home page (finally)
  • Notifications on iOS 10 include your motivating photo
  • There are more controls for when to show the photo on the home page
  • Lots of little bugs have been fixed


Developer Notes:

Habits most interesting to me as a hobby project — if you are interested,  you can also see my notes from 3.0 where I showed a screenshot of 1.0 — Habits was started almost as soon as the iOS SDK was officially released.

For this version, here are a couple of behind the scenes tidbits:

  • I ran the wonderful Synx on my project to finally align the folder and group structure.
  • I also introduced tailor into my commit procedure to enforce some Swift style.
  • I found my old svn repository for the beginnings of Habits — I am working on restoring that so that it looks like the pre-2.x history for what I have in git now.
  • I used to host my own git server repo, but that was mostly for backup. I decided to change my origin to bitbucket. I am thinking of one day open-sourcing Habits, but for now it’s private.

GitHub Profiles Update

The latest GitHub update includes some nice additions to the profiles page. A few years ago I wrote that you should never link directly to your GitHub profile in your resume or online bios:

GitHub’s public profile isn’t customizable and doesn’t do a good job of describing a person’s contributions. I recommend:

1. Create a page with a simple URL on your own domain (e.g. example.com/github) and write a narrative that takes me through your repositories.

2. Link to that page in your resume and in your GitHub profile.

I played around with my profile and even though it’s more customizable, my recommendation still stands: link to a page where you can put context around your profile.

In addition, I think it’s worth using the repository pinning feature to highlight the projects you would want someone to look at if they should get to your profile page some other way.


Handling Pluralizations Correctly in Strings

Earlier this year, Trello launched in 21 languages. I worked on the i18n effort of the iOS apps, and I have been collecting thoughts for a series of blog posts. The first one, about plurals, was published today on the Trello Tech Blog. It begins

On page 52 of my copy of K&R, in a discussion of the ?: operator, is this line of code

printf("You have %d item%s.\n", n, n==1 ? "" : "s");

And thus began my decades-long proliferation of plural-unfriendly strings.

To see why, read the rest of Lessons from Internationalizing Trello, Part I: Plurals on iOS

As a follow-up, I found a Russian translation of K&R. Here is how that line of code is translated

printf("Вы имеете %d элемент%s.\n", n, (n%10==1 && n%100 ! = 11) ?
    " " : ((n%100 < 10 || n%100 > 20) && n%10 >= 2 && n%10 <= 4) ?
    "а" : "ов");

Which is another way to do it, I guess.

iOSDevUK Lightning Talk about Swift Playground Books

Links from the talk

  1. Playground Book package format
  2. WWDC 2016 talk about Swift Playgrounds
  3. My fix of Talking to the Live View
  4. Ash Furrow’s playgroundbook command-line tool
  5. My PlaygroundSupportMock framework for building an app from a book
  6. My pgbookc script for turning a Contents folder in a host app into one that you run as a book
  7. My ShapeSearch playground book and host app built using those tools

Read my previous post on authoring a Swift Playground Book for more information.

Authoring an iOS Swift Playground Book

I expect at some point Apple will have some kind of Playground Book authoring solution, but until then, I’ve hacked together something basic that I am ready to share.

Take a look at my previous post if you’re getting started with playground books. The important things to know are:

  1. The book is a package with a specific folder layout of chapters and pages.
  2. The left-hand side is a stateless playground with markdown and code.
  3. The right-hand side is a stateful live view that can host a View Controller and do pretty much anything you could do in an app.
  4. The playground view and live view can communicate via a simple asynchronous inter-process communication mechanism.
  5. The book is delivered as Swift source files, assets, and plist config files.

As I mentioned in the last post, Ash Furrow has a way to generate this format from a .yaml description and playground files. Even if you don’t ultimately use it as your book source, it’s a good way to generate your initial package structure. The same project also has a linter, which you should use no matter how you author playground books.

The drawback of trying to write an entire book this way is that some of the code lives in the .yaml file and is hard to write and check.

I wanted a way to:

  1. Write the code in Xcode (to get autocomplete, docs, etc)
  2. Build it there too
  3. Run it in a host app where I could test the LiveViews in the simulator
  4. Unit-test the playground and LiveView code

I started by putting a book’s Contents folder into a skeleton app and loading the first page’s LiveView as my rootViewController. The first problem is that on the iPad, there’s a framework called PlaygroundSupport with support for Swift Playground features like the messaging between the playground and LiveView. This framework is not currently available in Xcode.

To make it buildable in Xcode, I made PlaygroundSupportMock. This is a work in progress, and I will add more support of PlaygroundSupport as I need it. You can add it to a skeleton app via Carthage.

The second problem is that the format requires each page folder to have a Contents.swift and an optional LiveView.swift. But, apps cannot have two files with the same name in the same module.  To get around that, I wrote a script called pgbookc to copy the Contents folder from the host app and rename any Contents-*.swift or LiveView-*swift files (removing the -* suffix).

Finally, there are several places in the book where code that would work in the book could not work in an app (and vice versa). So, I added a feature to pgbookc to look for special comments in the Swift files that help it to alter it to work as a book.  For example, here is some typical code you might find in a book (to send a PlaygroundValue dictionary to the LiveView and call it from the playground itself)

func hasAttribute(shape: Shape, attribute: ShapeAttribute) -> Bool {
    let attributes: Set = shape.attributes
    return attributes.contains(attribute)

hasAttribute(shape: cloud, attribute: .IsGray)

The problem is the last line, which must be at the top-level in a playground (but cannot work in an app).  So, pgbookc will look for any line that ends with


and removes that entire line. This lets you write:

func Contents0102() -> Bool { return // REMOVE LINE
hasAttribute(shape: cloud, attribute: .IsGray)

The first and last line will be stripped from the book, but it’s there for the app build. It’s also there for tests, which lets me write:

func testContents0102() {

To make sure any playground code in a Contents.swift file works.

I have an (almost done) Playground Book that I am writing using this technique. It’s called Shape Search and has the reader build a simple guessing game that teaches how to do a binary search.

Swift Playground Books: 2-Sep-2016

I imagine a lot of the information here is going to go out of date fast, but if you are looking at playground books today, here is where to start.

  1. The WWDC 2016 talk, Introducing Swift Playgrounds, has a lot of technical detail about the .playgroundbook format and how the LiveView proxying works.
  2. The demo for that talk is available on Apple’s dev site, but it’s out of date. I’ve been updating it for each iOS 10 Beta (to track Swift 3). Go to my GitHub to get the fixed Talking to the Live View sample.
  3. The documentation for the .playgroundbook format can be found on the Apple Developer site.
  4. Erica Sadun, who has written the book on Xcode playgrounds did some early investigations of iOS Swift Playgrounds. You might want to read them — here is Part I, Part II, Part III, Part IV,  and Part V.
  5. Ash Furrow made a playground book linter and authoring tool (source). You can use the linter on any .playgroundbook (however you make it), and the authoring tool allows you to specify the parts of the book in a .yaml file, and it puts each piece in the correct file and folder for you in the .playgroundbook package.

Habits 3.0

Back in 2008, I learned Objective-C to make my first “iPhone OS” app, Habits. When it was released, Habits looked like this:


This weekend I finally finished v3.0 and made it free.

As this is a developer site, the more interesting thing to note is that Habits was originally made in the first iPhone supporting version of Xcode (with external Interface Builder) and I have been migrating the project file from version to version since then (using 7.3.1 to make the current build).

Some things that were introduced into Habits for this version:

  1. Swift – all new classes were made in Swift and many existing ones were refactored into Swift
  2. Accessibility – Since NSSpain 2015, I’ve been running my iPhone with triple-Home to get into VoiceOver (suggested by Hermes Pique in this talk). Doing that made me realize (1) what it was like to use Habits without looking at it (2) how easy it was to make it work properly.
  3. fastlane – specifically “deliver” to manage the iTunes record and “frameit” for fancy screenshots
  4. Carthage – there had never been 3rd party libraries in Habits, but I decided that one was worth it this time.
  5. TOCropViewController – A simple framework that does one thing very well – provide a View Controller for cropping images. I use this instead of the built-in iOS one because it supports locked aspect-ratios.