Nick Harris

Archive for March 2016

PDF Playing Card Assets

leave a comment »

Xcode gave us the ability to use PDF (or single vector driven graphics) a while ago and I’ve never heard good or bad if they should be used instead of strict sized based PNG assets.

I’ve been playing around with them though with Euchre and Solitaire and I like how my PDF assets look on all my devices.

There was a sizable resistance against PDF assets a few years ago. Is that still the case?

Here are some screen shots of my PDF cards on a 4s, 5, 6, 6SPlus, iPad Air and iPad Pro…



5 (or SE)




6S Plus


iPad Air 2


iPad Pro



Those blog images are probably hard to judge from.

Here is my Sketch file and PDF assets I made.

Feel free to use them in your own apps.

But back to the original question…

Are PDF assets OK now?

Written by Nick Harris

March 23, 2016 at 7:16 am

Posted in Uncategorized

Selectors With Parameters in Swift 2.2

with 16 comments

I went back today and recompiled all my latest Swift projects  – Euchre, CloudKitPOC, Suntracker, Solitaire – to see how much Swift 2.2 would break them. The only thing that I got warnings about (I’m a 0 warnings dev) was about changing from string selectors to using the #selector() syntax. They were all warnings but I had problems fixing one of them. The “Fix-it” solution ended up being another warning.

In Solitaire I have a GameController and a GameViewController. The GameViewController is strictly UI only. There is no game logic what-so-ever in it. All of that is contained in the GameController. I also created a PlayingCardImageView subclass of UIImageView to handle all the interaction with the playing cards. For instance, tapping a playing card will execute any plays that card can make in the game.

When implementing this, I had to decide if I wanted pass the GameController into every PlayingCardImageView or have the target and selector of the UITapGestureRecognizer refer back to the GameViewController. I opted for the later. I only wanted one class to be responsible for passing user interactions back to the GameController.

My code in the PlayingCardImageView for 2.1 was:

let tapGestureRecognizer = UITapGestureRecognizer(target: gameViewController, action: "cardTapped:")

The “Fix-it” solution:

Screen Shot 2016 03 22 at 9 07 33 PM

which then lead to…

Screen Shot 2016 03 22 at 9 12 24 PM

Hopefully the first thing you’re thinking as a seasoned Xcode user is “Never use Fix-it!!” and you’d be right. Unless you understand what Fix-it is actually doing its much better to dig into the problem yourself and figure out what the fix should be.

The proper solution in Swift 2.2 for this is:

let tapGestureRecognizer = 
UITapGestureRecognizer(target: gameViewController, action: #selector(gameViewController.cardTapped(_:)))

It wasn’t the most obvious syntax to arrive at but at least I know now.

BTW – here’s a great rundown of Swift 2.2 changes. I’m looking forward to trying out tuple comparisons – particularly with my NSOperation operationResult tuples in unit tests.


I want to point out that I figured it out quite easily with Xcode code completion. I don’t want this post to sound like a dump on the Xcode team. Xcode gets better and better with every release! I bet its just a miss in the Fix-it logic.

Screen Shot 2016 03 22 at 10 03 02 PM 

Written by Nick Harris

March 23, 2016 at 3:37 am

Posted in Uncategorized

Klondike Solitaire Weekend Challenge

leave a comment »

Friday was a snowy day in Denver. There was a lot of basketball on TV too. I decided to give myself a challenge…

How hard would it be to write a Klondike Solitaire app for iOS?

The challenge was just to see how far I could get just on weekend evenings (my weekend days are not for coding). I was going to be watching NCAA tournament games so might as well have something to do during downtimes.

I think I got pretty far! Its not complete, but its easily less then a weeks worth of work to complete.

What isn’t there

– dragging between piles
– scoring
– different game rules (single card from the waste pile is all that’s supported)
– undo

Here’s my game on Phone 6S Plus:

Why Solitaire?

Klondike Solitaire has been a staple on both Mac and PC. After working on this I can see why. The logic is pretty easy. The challenge in the UI. Once you have solid game code the only challenge is passing user interactions into the games controller.

I bet that’s why its been a constant in OS versions for decades. The big challenges are always UI based. The code that drives my game is less then 700 lines of code all told. Its a really simple game with simple rules. I spent much more time figuring out how to make it work on multiple devices.


I’m both surprised at what I got done with 16 hours of work over three days as well as being a bit disappointed that I didn’t finish more. I spent much more time in UI driven roles (creating assists, dealing with Storyboard Autolayout) then I would have wanted too. I wonder how much of what I think is left i would had gotten done if I wasn’t fixated on having something in a video.

The total app is less then 1025 lines. I don’t see it getting more then 2000 when all is said and done.

Fun weekend and fun challenge though!

Written by Nick Harris

March 21, 2016 at 7:42 am

Posted in Uncategorized

Firing People

leave a comment »

Zach Holman wrote what may be my favorite post I’ve read in a very long time titled Firing People. The whole thing is fantastic and I highly recommend taking the time to read it all.

I’ve never been fired but I have been laid off as well as leaving on my own when things didn’t work out the way I had wanted. One was a failed product that I had invested so much of myself into but the company decided wasn’t worth continuing and the other was a role that I never quite figured out how to succeed at given the circumstances. In all those cases though, a lot of what Zach writes about really resonated with me.

One part in particular is knowing where you stand with stock options.

Unfortunately, vested unexercised ISOs are capped at 90 days post-employment by law, meaning that they disappear in a puff of smoke once you reach that limit. This poses a problem in today’s anti-IPO startups who simultaneously reject secondary sales, which limit all of the options available for an employee to exercise their stock (the implications of which for an early employee might cost hundreds of thousands of dollars that they don’t have, excluding the corresponding tax hit as well).

Another possibility that’s quickly gaining steam lately is to convert those ISOs to NSOs at the 90 day mark and extend the option window to something longer like seven or ten years instead of a blistering 90 days. In my mind, companies who haven’t switched to a longer 90 day window are actively stealing from their employees; the employees have worked hard to vest their options over a period of years, but because of their participation in the company’s success they’re now unable to exercise their options.

I’ve talked a lot about this in greater length in my aptly-titled post, Fuck Your 90 Day Exercise Window, as well as started a listing of employee-friendly companies with extended exercise windows. Suffice to say, this is a pretty important aspect to me and was a big topic in the discussions surrounding my separation agreement.

After 8 years at one company I had vested a lot of stock options. When I decided to leave it didn’t dawn on me until I got the formal paper work that it would cost me more then $8,000 to exercise all of the options I had vested and I only had 90 days to do it. There was no way I could spend that kind of money at the time so I lost a good portion of my options. I love the “Fuck Your 90 Day Exercise Window” quote. I burned a few bridges venting about my situation though I’ve since had some great conversations with the company’s founder and ex-CTO about it. If I’m ever in a situation again with stock options I’ll be sure to setup a savings account specifically for exercising them when the time comes without the shock of the price.

If you’re a company that does stock options, be sure you’re very open about how much your employees have vested and remind them of it often. Also be sure to let them know about exercising them in 90 days. I know more then one employee of that company that lost all their stock options because they didn’t know about the 90 day cutoff.

Another great idea Zach talks about it setting up an alumni group.

One of the very bright points from all of this is the self-organized GitHub alumni network. Xubbers, we call ourselves. We have a private Facebook group and a private Slack room to talk about things. It’s really about 60% therapy, 20% shooting the shit just like the old days, and 20% networking and supporting each other as we move forward in our new careers apart.

The same company I spent 8 years at has one and its great. Its not a very active group but when someone is looking for something new, or if someones new employer is hiring, it gets posted to everyone. When the company had a round of layoffs last year the alumni group welcomed them all in easily hitting that 60% therapy mark. It was great though. I really appreciate that group. In fact I’ll be heading to the early round games of the NCAA tournament tomorrow here in Denver with a former co-worker who was just laid off from another job last week. I can guarantee we will be talking about companies we’re looking at since we already have been.

There’s a lot of other great stuff in that post. You should really go read it.

Written by Nick Harris

March 17, 2016 at 2:49 am

Posted in Uncategorized

Trouble Everyday

leave a comment »

Just spent another night watching another round of US politics in action on the old TV.

Trying to wash my mind of it I went looking into my music library and was reminded of a conversation I had after the third Ween show I was at last month. As the lights came up in the crowd the PA started playing “Sloop John B”. My buddy turned to me and asked what song it was.

Me: “Beach Boys? Pet Sounds? Arguably one of the most important albums ever recorded? Really? You don’t know this song?”

I’m a huge Beatles fan. Pet Sounds was a big influence on Sgt. Peppers.

I’m also a huge Frank Zappa fan. Freak Out was also a big influence on Sgt. Peppers.

A -> B -> Z – Z being Zappa.

The tie back to Zappa being the political environment we’re in – specifically with the song “Trouble Every Day” on Freak Out.

Trouble Every Day is about the Watts Riots in LA in 1965. The lines about race are powerful but what has always stood out to me are the lines about the media.

This song is 50 years old.

50 years and its feels like we’ve gone nowhere.

At least we have some good songs.

Written by Nick Harris

March 16, 2016 at 7:41 am

Posted in Uncategorized


with one comment

Icon 120

Introducing Suntracker!

Suntracker is a simple app that uses Core Location to determine a users location then calculates sunrise and sunset times along with total daylight for the location based on the NOAA Sunrise/Sunset Calculator. Suntracker shows you a graph of 3 months, 6 months or a years worth of daylight time and the ability to drag you finger across the graph to see individual days. The today extension shows the days sunrise and sunset times along with how many hours and minutes the day has of sun light. Suntracker will also notify you each day when the sun rises and sets – even on your Apple Watch!

Built using iOS 9 and Swift 2, Suntracker is designed for use on iPhone 4S through the iPad Pro. Much attention has been paid toward battery usage as well as accessibility. It supports large and bold fonts on all devices as well as multitasking on all iPads.



4SPortrait    4SDayDrag


6S Plus

6SPlusPortrait    6SPlusLandscape


iPad Air 2




Today Extension and Apple Watch




Suntracker is only available on BitBucket for developers.

Do not release this app or its assets as your own. The code and icon are my copyright. If you’re interested in building an app like this I would encourage you to use EDSunriseSet.


Suntracker started as an idea a few years ago. I had spent months writing my book and wanted an idea to play with to get me back into everyday coding. It was the beginning of February at the time and I was interested in the sunrise/sunset times of each day as the calendar moved from Winter to Spring. I found the NOAA Javascript calculator and decided to port it to Objective-C. I had enough code to make the calculations based on Core Location but I never built out the UI.

Fast forward 2 years to this past February and again I was in search of a side project. Translating Javascript to Swift was interesting to me but I also wanted to take some time to do something more with Autolayout on multiple devices along with dynamic text. I ended up learning a lot more about Core Location along the way.

Code Highlights

Core Location

I spent a lot of time getting my head around all of the different ways to use Core Location. I ended up with an approach that asks for location data even in the background but still supported using location only while in-app. With iOS 8 you have the opportunity to supply strings explaining why the app needs location information using the NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription keys in your info.plist. You can choose which you prompt the user for, but you only get one shot at it. I opted for always on but the user can change that in the Settings app if they wish:

4S Settings

When allowed background updates I used startMonitoringSignificantLocationChanges. The documentation for Core Location seems lacking to me but it felt like I could get the best experience while using the least amount of battery this way. I really wanted to use differed location updates but that only works by using the GPS radio with the best accuracy. This app doesn’t need GPS. Wifi or local cell tower triangulation are fine which is what I get with startMonitoringSignificantLocationChanges. I spent a few days with different devices driving around town while leaving others at home and everything worked as expected.

When only allowed in-app location access the code calls requestLocation. The system gives you one location then stops location monitoring. For an app like this its fine but the delay on launch to get a location is a bit annoying.

The Today Extension was more difficult. I couldn’t find a way to use CLLocationManagerDelegate in any way so it just uses the location property on the manager.

Here’s the function that gets called anytime the app is launched or comes to the foreground:

func handleLocationManagerStatus(status: CLAuthorizationStatus) {
    switch status {
    case .NotDetermined:
        // need to ask for location permissions
    case .AuthorizedAlways:
        // register for notifications only when location permissions have been granted
        UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[ .Sound, .Alert], categories: nil))
        // the app doesn't need a precise location so no need for GPS which will impact battery use
        // instead use significant location changes
    case .AuthorizedWhenInUse:
        // register for notifications only when location permissions have been granted
        UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[ .Sound, .Alert], categories: nil))
        // if we're only allowed in-app locations theres no need to get location updates as its highly unlikely the user will
        // be moving great enough distances to alter sunrise/sunset times. Instead just request the current location
    case .Denied:
        // we need to be sure the view is loaded so the alert can be presented
        if let sunTrackerViewController = sunTrackerViewController where sunTrackerViewController.isViewLoaded() {
    case .Restricted:
        // we need to be sure the view is loaded so the alert can be presented
        if let sunTrackerViewController = sunTrackerViewController where sunTrackerViewController.isViewLoaded() {


This is another app based primarily on NSOperations. After years of messy block to block implementations, I can’t imagine not breaking functionality into operations. The push toward functional programming aids in that thought. What I like about Suntracker is the one operation that calculates sunrise/sunset and other auxiliary operation groups that use it to complete the app.

I wrote about using tuples to pass data into operations and getting results out using operationInput and operationOutput properties. I really like the approach and plan on continuing that pattern. For example:

class CalculateSunriseSunsetOperation: NSOperation {
    // MARK: Public Properties
    var operationInput: (coordinate: CLLocationCoordinate2D?, date: NSDate?)
    var operationResult: (error: NSError?, sunriseTimeInMinutes: Double?, sunsetTimeInMinutes: Double?)
    . . . 

Just yesterday I saw a post about tuples being lightweight / limited scope structs. I think that’s a fair comparison.


I had been using enums for constants such as user default keys. I like that since it groups like values together but I was using rawValue everywhere which wasn’t ideal. For Suntracker I decided to use a struct instead. Here are my user default keys:

struct SuntrackerUserDefaultsConstants {
    static let UserDefaultsSuiteName = "group.cliftongarage.suntracker"
    static let SunriseTimeUserDefaultsKey = "SunriseTimeUserDefaultsKey"
    static let SunsetTimeUserDefaultsKey = "SunsetTimeUserDefaultsKey"
    static let TotalDaylightUserDefaultsKey = "TotalDaylightUserDefaultsKey"
    static let DaysUntilDSTSwitchUserDefaultsKey = "DaysUntilDSTSwitchUserDefaultsKey"
    static let LastLocalityUserDefaultsKey = "LastLocalityUserDefaultsKey"
    static let LastDayCalculatedUserDefaultsKey = "LastDayCalculatedUserDefaultsKey"
    static let SunriseNotificationsUserDefaultsKey = "SunriseNotificationsUserDefaultsKey"
    static let SunsetNotificationsUserDefaultsKey = "SunsetNotificationsUserDefaultsKey"
    static let LastLocationFetchUserDefaultsKey = "LastLocationFetchUserDefaultsKey"
    static let LastStringsOperationUserDefaultsKey = "LastStringsOperationUserDefaultsKey"
    static let SelectedTrendChartUserDefaultKey = "SelectedTrendChartUserDefaultKey"

They’re still grouped but there’s no need for rawValue everywhere in code to use them. Much better!

Today Extension

Suntracker also has a Today Extension.

I found developing for the Today view incredibly frustrating. I’d like to see data on how many users enable a today widget to determine if the struggle is worth the effort. As an iOS user I can’t imagine it is. I’ve seen some say they use the Today view often but personally I don’t.

What frustrated me the most was the odd auto layout constraints as well as the inability many times to connect the debugger. It was hard to tell if I could rely on the widgetPerfromUpdateWithCompletionHandler to get called every time the user viewed the Today panel. I found some saying to call code to update the view in viewWillAppear as well so that’s what I ended up doing.

Shared NSUserDefaults

Setting up shared NSUserDefaults was fun. Just make sure your user defaults suite name is exactly the same as your app group identifier.

Dynamic Text

Dynamic text was more difficult to support then I would like. Not because its all that hard but designing a user interface that would react well was difficult. Layouts that looked fine at regular size look horrible at large and bold. In the end I decided that calculated values were more important then simple labels so I went with shrinking the simple labels in order to keep the calculated values large. For instance, here’s a 4S in landscape with the largest text set to bold:



This app was a lot of fun to finish. I spent a good portion of time working with Core Location and battery usage in order to get the best user experience but I think that time was well worth it. Also spending more time playing with auto layout in different size classes using different accessibility settings was great. I can’t imagine being a developer with a single test device though. I wrote this app using my 4S, 5, 6, 6S Plus, iPad Mini, iPad Air and iPad Pro. I needed all of them in order to find issues with device speed and well as layout differences.

All in all I’m just happy Spring is here! 

Code is available on BitBucket.

Written by Nick Harris

March 9, 2016 at 10:53 pm

Posted in Uncategorized


leave a comment »

Denver was named the #1 place to live in the United States today by U.S. News & World Report. I’ve lived here for almost 15 years now and I can attest that its very true. The people are great, the natural beauty is breathtaking and the job market is amazingly robust. Even during the big bust of 2008 when the company I worked for had to layoff a good percentage of employees, my friends that were let go had offers from other great companies in short order. 

I spent a good portion of last year deciding if I wanted to stay in Denver or move to somewhere new. I visited a bunch of cities – Raleigh NC, Washington DC, San Francisco CA, Seattle WA, Chicago IL, Madison WI. I loved them all and had a really hard time deciding which I liked over all the others. But in the end I decided the place I really wanted to be was here in Denver. 

I live 5 miles from Red Rocks. I have friends here from high school and college who are basically family after 20+ years. I can take a lunch break and drive up the canyons and switchbacks to views like this and be back before afternoon meetings.

IMG 2196

I’m about to start a new job search. After 5 years of remote work I’m particularly interested in working in an office again – maybe even a startup again – though remote work isn’t out of the question. What is out of the question is leaving Denver even if that means missing the opportunity to work at some pretty amazing companies. The only thing that could really draw me away from Denver is to be closer to my family in Ohio.

It wasn’t an easy decision to come to but its one that I have no doubts about. Denver is that awesome.

Written by Nick Harris

March 3, 2016 at 6:05 am

Posted in Uncategorized