A Dual Language Future

The Swift Programming Language book states that Swift is "designed to scale from 'hello, world' to an entire operating system." This has troubled me from the start, and I brought it up again recently on Twitter:

http://twitter.com/amolloy/status/735105280388804609

My basic issue with the idea is that it involves a very simplistic view of the problem space programmers work in. It assumes that the tools required by a programmer developing, say, a compiler are the same as those required by a programmer working on an app. But, as someone who has worked on both compilers and apps (and games, and servers, and so on), I feel pretty strongly that this is simply not true.

Continue reading

Entangler 2.1 Waiting for Review

Entangler 2.1 is in the can and waiting for review. Here's what's coming:

iOS

  • Entangler now lets you know when your action has completed.
  • Added a support interface where you can file support requests and view the FAQ.

Mac

  • Fix an issue where, if you opened the Entangler window too soon after launching it would never populate with your actions.
  • You can now choose an application when selecting a custom icon for an action. The action will use the selected application's icon.
  • Fix an issue where an action's icon may not update correctly when changing background color.
  • Hold down the Command key while clicking the "+" button to open your scripts folder in Finder instead of starting the import process.
  • The on-boarding process now directs you to the EntanglerApp.com web site for support and the action gallery.

Both

  • Fix the "Establishing Entanglement" dialog never disappearing for new users (this is the most important of the bunch as far as I'm concerned).
  • You can now set actions to expire if something prevents them from firing immediately, such as your Mac being turned off.
  • More robust data synching and cacheing.
  • Fix an issue where, if you had actions with the same name on multiple Macs, triggering the action on any Mac would cause it to fire on all Macs.

As excited as I am to get this new version out to you good folks, I don't expect to release it until early January (assuming Apple approves it by then). I'd hate to have shipped a nasty bug and not be able to address it even with an expedited review until after Apple finishes their holiday break.

 

Swift

Just shy of two weeks ago, Apple announced their new programming language Swift at WWDC. Apple stated that Swift was Objective-C without the C, and presented it as where things are moving. It is a very exciting time for Apple developers in general, and this new language is just the tip of things. So of course, I dove right in!

I’ll state right off the bat that I have mixed feelings about Swift. As I1 quipped on Twitter, it’s not just Objective-C without the C, it’s Objective-C without the Objective-C2. The language makes a number of tradeoffs that I feel are questionable. It involves concepts that sound great on paper, but in practice likely won’t work out (how many programmers do you think will actually bother to properly check optionals before !‘ing them? I will, and I know you will, but what about Bob down the hall?).

That said, there is a lot to like about the language, and a lot to be excited about. Pointers are hidden away so we don’t have to type the asterisks anymore. Enumerations in Swift are a vast improvement over anything offered by the C family of languages. Tuples are first class members of the language (of course they will be abused to return errors along with results, but you have to take the good with the bad).

Unfortunately my current day job doesn’t involve Objective-C or Swift, so I’ve only had the opportunity to use it on the evenings and weekends. Still, this has been enough time to completely convert a new project that I recently started from Objective-C to Swift. In the process I came across a number of issues with the language to report to Apple, which I’ve listed below in no particular order:

I also have a handful more that I am still digesting a bit before reporting them.

If you look through those, it’s very apparent that I have some strong disagreements with many of the decisions made in the design of the language. Most of them are unlikely to be addressed in a way which satisfies me, but that’s ok. I reported the issues because I like the idea of Swift and the initiative Apple is taking by introducing it, and I want it to be better. And while Apple is busy either fixing or discarding my issues, I will do what I always do: program in whatever language seems best suited to the task at hand, be that Objective-C, Swift, or something else.


  1. And I’m sure many others.
  2. Really, it’s like Objective-C through the eyes of someone who has maybe seen a lot of Objective-C, but produced almost none of it.

50 Down, 20 to Go

A bit under a year ago, I told my story of how I had “let myself go” over the years, and encouraged others not to follow my path. In that post, I talked about what I have been doing to try to reverse course. To my surprise, over the past year it’s been one of my most popular posts1. I hope those who stumbled on it found it useful. In the meantime, I’ve continued to work towards getting back into healthy shape. I figured now was as a good a time as any for an update.

Since that post, I’ve mostly continued exercising in some form or another three days a week. There were a few weeks early this winter where I fell off the path. I had plenty of excuses; the weather was bad, at several points various members of the family were sick, including myself, etc.

Eventually I kicked myself in the butt and made myself get back to it. I had no desire to jog in the frigid temperatures we had, or the foot of snow still on all of the sidewalks and jogging paths. So I started riding my wife’s stationary bicycle. I have to ride longer to burn as many calories as I do jogging, but I can watch TV while doing it – a nice bonus. Now that the weather is getting nicer, I’ve been out to jog a few times. I have enjoyed the bike, but I am looking forward to making jogging my primary exercise again. Soon.

I’ve also made more changes to my diet. My body seems to finally be adjusting to taking fewer calories in. I’m not hungry all the time any more. And, recently, I started eating quite a lot more fruit. For the first time in my adult life, I head to the produce section first thing when I go to the grocery store to pick out some apples and mandarine oranges. Such a simple thing, but I’m sure it’s made a huge difference.

The net result? Over the past two years or so, I’ve lost about 50lbs. I’ve gone down a pant size. My wedding ring is now too loose and needs to be resized2. I feel and look much healthier. I feel good about setting a good example for my kids3. This is a chart I feel pretty darned good about:

WeightChart

I’m feeling great, but I have work yet to do. I still have 20lbs to reach my goal weight, and I’ve recently hit a plateau. I’m not going to worry about that plateau too much yet. With spring finally here I’ll be back to jogging, which I sense is a better workout than the stationary bike. If after a few weeks of jogging I’m still on that plateau, I’ll start considering doing something more. But as mentioned above, I want to do this right, with the goal being my overall and lasting health. That means being patient. I think I can do that.

If you found this post because you, like me, had let yourself go, I hope this serves as motivation to get back into shape. It’s hard – boy is it hard – but also possible and absolutely worth it. Make yourself do it, you won’t regret it. Good luck!


  1. My most popular post, for whatever reason, is Scan-build with Daily Clang in Jenkins. I hope I helped you, too, CI folk!
  2. As soon as I find it… Yeah, it apparently came flying off a few weeks ago and hasn’t been seen since. My best guess was that it came off while I was shoveling snow and it would turn up when the snow melted. Well, the snow is all gone but the ring is still nowhere to be found. At some point we will very likely give up and I’ll get a new one (of course, as soon as I do the old one will show up). My wife and I know we love each other regardless of that symbol, so while I would really like to find it we aren’t worrying too terribly much about it.
  3. Not that they really need it, those the skinny little buggers.

Doing it Right

Recently I decided to make Sunrise free - a decision I discussed here. Unsurprisingly, this drastically expanded the app’s exposure. Of course, more users means more potential for bugs to be uncovered. Sure enough, a new customer reported to me that in his location, the sun rise and set times were all exactly two hours off.

My gut told me this was a time zone issue, and indeed my gut was correct. This customer is in Hokkaido, Japan. Hokkaido is in the Asia/Tokyo time zone, which is GMT+9. However, the library I use for getting the time zone for a location (APTimeZones) was returning Asia/Sakhalin, which is GMT+11. APTimeZones uses a relatively naive algorithm to determine the time zone a location is within. Basically it maintains a collection of locations and their respective time zones, then finds which the query location is closest to. The results can be improved somewhat by providing the country code your location is within - and, indeed, that would have fixed this particular customer’s problem.

But, I decided that wasn’t good enough. There are still going to be locations where this algorithm fails. In fact, checking the APTimeZones issues reveals at least a couple other locations which fail. The only way to be absolutely certain you get the correct time zone for a location is to use the time zone shapes, not a distance-to-points algorithm (even that is not perfect as localities may change their time zone or not have well defined shapes).

Fairly recent time zone shape files are available from a handful of locations. There also exist libraries to interpret these files and do the appropriate sort of queries on them to accomplish my goals. There are even a few open source libraries for doing just this thing, though most of them are either in a scripting language like Python or are released under licenses I don’t feel comfortable using in an iOS app (I’m looking at you, LGPL). Going this route it appears I would have to implement it myself, which is not necessarily a bad thing.

An alternative is to use an online service to gather this data. There are a handful of choices for this, including Yahoo, Google, and others. Google’s offering allows 2,500 requests per 24 hour period for free, while the others either have no free usage level or allow free access to only certain classes of developers. If I went this route, Google was the obvious choice.

Sunrise is almost entirely an offline app. All of the calculations are done locally on your phone. I liked the idea of keeping it that way, which made the first option seem very attractive. I always enjoy the challenge of implementing something new. Plus, I could almost certainly isolate the functionality into a library and release it as open source. I am happy to contribute to the community any time I can.

But, the one time Sunrise does use a network connection (when adding new locations) also happens to be exactly when it needs to perform a time zone lookup. That code is already arranged to run asynchronously, so adding another step to the execution chain would be relatively trivial. And while performing an HTTP request is nowhere near as challenging as doing geospatial queries, I haven’t yet had the opportunity to work with NSURLSession at all. The simple requirements of using Google’s Time Zone API would be a nice, very basic introduction to NSURLSession.

With all of that in mind I decided that, for now, I would go with Google’s Time Zone API. The API involves a single URL request per location, and returns query results as JSON data, which can be dealt with trivially on iOS. Getting it integrated was fairly easy, and the benefits were immediately clear when I tested against a few locations APTimeZones has trouble with. In the off chance that querying Google fails, Sunrise will fall back on APTimeZones. With that, I could have easily called it a day.

But, I didn’t. While Google’s limit on calls to the Time Zone API are very generous, and I have difficulty imagining Sunrise going over it, I figured minimizing calls to it could only be a good thing. Dealing with this for saved locations is trivial, I just store the time zone name along with the location. But Sunrise also keeps track of the phone’s current location (if you allow it to). For a number of reasons, including user settings, the phone’s reported time zone does not necessarily reflect the time zone the phone is currently in. For this reason, whenever the phone undergoes a significant location change it performs a time zone lookup. This also happens every time it is launched.

So I decided to cache time zone location lookups. I could have easily done this with a plist file, but decided to go back to my old friend SQLite. Sunrise now creates a simple SQLite database in the application’s caches folder. Each entry consists of a latitude, longitude, and the time zone name for that point. Whenever a time zone is requested for a location, the cache is consulted first. I wanted to avoid the problems APTimeZones encounters, so I kept the cache resolution fairly small - 1 km. Dave Addey posted on his blog a great SQLite distance function that is very useful for just this sort of query. I use FMDB which has a nice blocks-based facility for adding functions to SQLite, so I adapted Dave’s code to work with this API. The result is a fast, lightweight store for the time zones cache.

These changes will probably only affect a small number of people. APTimeZones does return the correct time zone in the vast majority of cases. But it would be a disservice to my customers to not handle those cases where APTimeZones fails. These changes, which have been submitted for review to the App Store, make sure that Sunrise is Doing It Right. Regardless of any financial benefit Sunrise might bring me, this knowledge is plenty reward for me.

Sunrise 1.2 is Out, and Free

I never expected Sunrise to sell very well, and I haven’t been disappointed. It’s a rare thing to sell a copy of it in a week. This is not surprising, it’s an app filling a need very few people have in a niche market that is already extremely crowded. Still, I made the decision to try charging for it. After all, it is (in my most humble of opinions) a very nice looking app, as pleasing to look at as it is to use, and certainly far nicer than most of its direct competitors. But, charging for it was not working.

So, today I am pleased to announce that Sunrise is now free.

For those who find the app truly useful, I’ve added a “tip jar,” as pioneered (or at least popularized) by David Smith’s Pedometer++. There are three levels of tips, and they are completely optional. They won’t unlock any new functionality, though if enough people give me tips it may well encourage me to continue to improve the app.

I tried to make the tip jar as unobtrusive as possible. It is not visible anywhere on the main screen, you’ll only see it when changing locations. Once you’ve given a tip it disappears completely, and for those who purchased the paid version of the app it never appears at all. I don’t want to bug people about it, and I think the way it is implemented succeeds at that. It’s very possible I’ve made it too unobtrusive, but I would much rather people give me tips because they want to than because I’ve begged them to.

Of course, this isn’t the only change in the app. The app had major performance issues on the iPhone 4 and iPad 2. This update improves the performance on those devices significantly. The sunlight view now uses higher resolution images of the Earth on the iPad. There are also a handful of bug fixes, such as making sure the Add Location text field is always above the keyboard (an issue on 3.5" devices).

Sunrise 1.2 is now available on the App Store - please go check it out!

Technical Info

Getting the app to perform better on older hardware involved a number of changes. For example, the first use of an NSDateFormatter can be very slow on the iPhone 4. This is not really a surprise to me; BabyGrow, for instance, only ever creates a couple NSDateFormatters for this reason. Still, it caught me off guard seeing it so high up while I was profiling. Creating one NSDateFormatter for each format I needed and keeping them around helped tremendously.

But the big one I discovered almost by accident and really should not have been surprising to me. Prior to Sunrise 1.2, the images of the Earth used in the sunlight view were 640x320 - exactly the size for the portrait view on the iPhone. Anyone familiar with OpenGL will probably already see what the problem was. I have enough experience with OpenGL that I should have, too. So, what was the problem? The image’s dimensions are not power of twos. This is a big no-no in OpenGL-land. On some hardware it is maybe not ideal but works well enough for Sunrise’s purpose. On the iPhone 4 and iPad 2, though, it was a major performance drain. Resizing the images to have power of two dimensions was a huge win on older iOS devices.

Lastly, a note about the tip jar. I only expect any given customer to purchase at most one tip, and only purchase it once. To me, this made the “Non-consumable” in-app purchase type make the most sense. However, the update was initially rejected for this. From Apple’s point of view, “tips” are considered a product and their guidelines require that products be implemented as “consumable” in-app purchases. I find the logic behind this… questionable. Especially considering the pains I’ve taken to make sure the tip jar disappears for a user completely once they’ve purchased a tip, never to return. Nevertheless, I didn’t feel that it was worth challenging the app review team on this, so the tips are now implemented as consumables. If you’re reading this and considering trying a “tip jar” in your app, skip the rejection and go ahead and make your tips “consumable”!

Otto’s Remote Quick Update

Otto’s Remote 1.3.3 is now available! I’ve decided to try releasing several incremental updates for Otto, and this is the first of those. The headline feature for 1.3.3 is the addition of a search bar in all of the actions tables. This should hopefully help those of you with a ton of actions.

In addition, Otto’s Remote can now do something like variable substitution in command line arguments passed to your scripts. There are a handful of variables, and they work with both immediate actions and geo triggers. So far, most of these are related your iPhone’s location and will probably be most useful in conjunction with geo triggers. The available variables are:

Variable Description
device The name of the device which triggered the action
latitude The device’s approximate latitude when the action was triggered
longitude The device’s approximate longitude when the action was triggered
altitude The device’s approximate altitude, in meters, when the action was triggered
horizontalAccuracy The radius of uncertainty for the location, measured in meters
verticalAccuracy The accuracy of the altitude, measured in meters
speed The instantaneous speed of the device in meters per second
course The direction in which the device was travelling

To pass any of these in to your script as command line arguments, wrap the variable name in double square brackets. For example:

“[[device]]” [[latitude]] [[longitude]]

will pass three arguments to your script, the device’s name, latitude, and longitude. Currently Otto’s Remote does a dumb substitution of the variable values into your arguments string, so if your device name has spaces in it (very likely), you’ll need to quote it to make sure it is interpreted as a single argument, as shown above.

That’s it for now. Enjoy!

Sunrise 1.1 Coming Soon

Update 1/16/14: Sunrise 1.1 is now available. Go grab it!

Thanks to Crashlytics I have learned that Sunrise 1.0 crashes - a lot. Fortunately, it would be very surprising if any of my customers have noticed, as the crash occurs when the app is in the background. The only sign the app has crashed is the next time it is launched it shows the launch animation instead of going straight to the main screen, which could happen anyway if iOS has decided to shut it down.

The crash itself was pretty easy to diagnose. Something was causing the Earth sunlight view to redraw, even though the app was not active. This view uses the fantastic GPUImage library to draw itself. GPUImage, in turn, uses OpenGL ES. On iOS, if an app is in the background and calls any OpenGL ES function, it will be forced into a crash.

The question then was, why is the sunlight view being redrawn? I had never reproduced the issue locally, so I had to work just from the crash log and my knowledge of how the app works. Fortunately, it didn’t take too much digging to discover the source of the problem, along with why I hadn’t ever reproduced it. Basically, the app requests the user’s current location and asks iOS to keep it informed of major location changes. If the location changes while the app was in the background (a common occurrence, it turns out), the sunlight view tries to update and the app crashes. This is a pretty obvious issue and one I shouldn’t have shipped with, but my crack QA team (read: me) missed it. Since the app really does not need to update while it is running in the background, the fix was to turn off location updates when it leaves the foreground. This has the added benefit of not causing extra drain on the device’s battery if it is the only app that has requested location changes.

Sunrise 1.1 also cleans up the sunlight view’s rendering shader, mostly for my own benefit (though it is a tiny performance win as well). I also added an indicator to the sunlight view to show the selected location. There are one or two minor bug fixes in there as well.

Sunrise 1.0 is now available in the App Store, and 1.1 will be available soon. Please check it out!

More About Sunrise

Sunrise’s life started because I was curious about how often my son and I would be standing in the dark while waiting for his school bus in the morning. There are plenty of websites and apps which give the sun rise and set times for the current day, but I wanted to look at a range of dates. There are websites and apps that allow you do this, as well, but as far as I could tell they all only showed the facts for a single date at a time. I wanted a way to see the rise and set times for a range of dates all at once. Thus was born the topmost view in Sunrise:

Top View

This view shows the sun rise and set times for the entire year, with the current date in the center. I’m sure I’m not the first to come up with this way to present this information, but I haven’t seen it before. I originally had lines to represent every couple of hours as well as vertical lines with date labels, but this was far too busy. Now you can find the exact sun rise and set times for different dates by dragging across the view. The result is a view that presents a lot of information at once (sun rise and set times for an entire year) in a sensible, easy to understand manner which still allows you to dig down and get to specific information if you want.

In all honesty, I was going to stop at this point. I wasn’t designing a product, I just wanted to see how much time my son and I would spend standing in the dark. But I liked this presentation of the data a lot, and so did everyone I showed it to. Nobody I showed it to had seen anything quite like it before. So I decided to flesh it out and have a go at selling it.

Of course, this view only took about a third of the screen. What should I fill the rest of the screen with? I initially considered a simple table of additional sun facts: the various twilight times, solar noon, etc. But while that information is surely useful to a number of people, it didn’t really feel right for this app. I wanted the app to appeal more to people who are simply curious about the brightest star in our sky and how it interacts with their lives. Once I had made that decision, it was obvious to me what the next bit of information to display would be: the sun light map of the earth:

Bottom View

I always enjoy these sorts of maps, I think they are both fun and informative to play with. I had also implemented one before, though that was a few years ago and I no longer have the source to it. My memory of the math involved was not as good as I had hoped, but eventually I got it together. I used GPUImage with a custom filter (read: fragment shader). The Earth images are taken from NASA’s Blue Marble Next Generation series of images. One neat detail you might miss if you don’t play with the date (by dragging around in the top view) is that the map uses the appropriate images for the time of the year, so you can also see how the earth changes throughout the year.

After this, I still had about a third of the display to fill (on tall iPhones in portait orientation - iPad and older iPhone support didn’t come until later). The last bit of information to display was less obvious to me. I finally settled on the sun’s elevation for two reasons: I was fascinated by how low the sun’s highest elevation is this time of the year here in Carmel, IN (~30°) and it gave me a way to allow users to adjust the time of day in the sun light map. So, sun’s elevation throughout the day it was:

Middle View

Watching how the sun’s elevation chart changes throughout the year is pretty fascinating. Be sure to check it out for locations at very high latitudes, such as Vardø.

I had to spend some time optimizing to get reasonable performance on the iPad 2 and iPhone 4. This project definitely demonstrated why you should never optimize without profiling: only one of the things I thought might be a performance problem was. Several bits of code that I was certain would have been hot spots barely even registered while profiling. Every actual performance issue was a complete surprise.

Sunrise is now available in the App Store, please check it out!

Introducing Sunrise

Today I am proud to introduce my latest app, Sunrise.

en-iphone5-portrait-selected_date_time

Sunrise presents key information about the brightest star in our sky: the sun. With Sunrise, you can:

  • Get sun rise and set times for your current location and anywhere in the world.
  • See the sun’s elevation above the horizon throughout the day.
  • Explore how the Earth is lit by the sun at different times of the year.

Sunrise is now available in the App Store. Please check it out!