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:
Swift – all new classes were made in Swift and many existing ones were refactored into Swift
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.
fastlane – specifically “deliver” to manage the iTunes record and “frameit” for fancy screenshots
Carthage – there had never been 3rd party libraries in Habits, but I decided that one was worth it this time.
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.
I am not a TDD zealot (or even really a practitioner), but on The App Guy podcast, Paul Kemp asked me if I had any habits to share as an app developer. I said:
My app developing habit … is get a new passing unit test every day. […] that new green dot is my indication that I’ve at least added a little bit to the application.
This is a habit I started in earnest when I took B. J. Fogg’s Tiny Habits course. My tiny habit was to just run the simulator, and the best way I found of doing that was to run the tests through it. Then, writing a new test for whatever functionality I was planning next just seemed to be the perfect way to extend it.
Once I write that first test, I don’t TDD the rest of the way, but I’ve found that first test to be a good way to warm up.
You can have both versions of Xcode on a machine simultaneously.
Here’s what I did
I installed Xcode5 normally
I downloaded Xcode 4.6.3 from the Apple developer website and copied that into my Applications folder as Xcode_4_6.app
I downloaded the iPhone/iPad iOS 7.0.2 ipsw’s from the developer website and loaded them into the 4.6.3 Organizer (Devices -> Library -> Software Images).
In order to get Xcode 4.6.3 to see an iOS 7 device, you need to start Xcode 5, load a project so that it connects to the phone, and then exit Xcode 5 and start Xcode 4.6.3, You periodically need to do this again (probably whenever you restart Xcode, but not every time you plug in the phone)
One annoyance is that both versions share Recent Projects and will automatically open projects that are open in the other one. It’s usually best to only start one if the other is closed or doesn’t have any projects open.
If you build iOS apps and send the IPA to others to install, there are a few simple checks you can do before you send it that will make sure it will work.
Go into your Build Settings and set the “Validate Built Product” to Yes — that way you won’t be able to build if your provisions are wrong. This is the default for new projects in recent versions of Xcode, but check it to make sure.
Open the IPA that was created. It’s a bundle, so copy and rename the extension to .zip. Then look for the mobileprovision XML file. You should see the device UDID that you intend to send it to.
Always increase the version # of any build that leaves your machine. If you don’t do this, iPhone Utility or anything else can decide to offer a cached version instead. If you have a good place in your app to show the version, do it.
If the device isn’t listed in the mobileprovision file, then make sure it’s added to the provision in developer.apple.com’s certificate area. Regenerate it and download it once it’s right.
Even if you are using a system like TestFlight, you should follow these tips. TestFlight can’t make an invalid app work, and it can’t fix an IPA that doesn’t have all of the device UDIDs in it. All it does is automate over-the-air IPA installs (which is great), but it still operates within the confines of the app distribution system.
I’ve been running iOS7 for a few weeks now as I refresh the look of my apps. Habits is kind of getting there, but I’m trying to internalize the design lessons of iOS7. Basically, my mantra is, “no pixel left behind”, which means
If I can change the color of a pixel with no loss of semantic meaning, make it the background color
If I can add meaning with space and grouping, do it, and remove more pixels
If I can add meaning with color, do it
It’s ok to have “brand” colors, but use them only when you need contrast
Here are some other lessons
Prefer to reveal more UI rather than navigate
Make gestures feel like they are moving a physical object (e.g. use pan instead of swipe)
Prefer fewer words, but use enough to not be distracting
Habits 2.02 should be ready in a week with these lessons applied.
If you want to show off the power of your programming language, nothing works better than a cool one-liner (or even better, a code tweet).
I have to program in a few different languages, of varying degrees of power, and one thing you start to notice is the 0-liners — the code that just doesn’t exist.
An obvious example is how garbage collection (or ARC) gets rid of memory management. Here are a few more examples:
In Objective-C, nil sinks messages. This means that in a lot of cases, you don’t have to check for nil and “the right thing” happens automatically. If you send nil a message, it’s a no-op, and if you need a return, you get 0 for scalars, nil for objects, 0-filled structs, and undefined for anything else. You still consider the nil case, but you usually don’t need to write any code.
This is a real example of a language completely implementing a design-pattern, in this case Null-Object. You can get similar behavior by using this pattern. Clojure does even better by letting you implement a protocol on nil to provide implementations for its functions called with nil. But, neither of those are 0-liners.
I don’t use F# (or Scala), but my understanding is that when Some/None discriminated unions are used in computation expressions, the computation will end and return None if some part of the expression returns None. This is a classic 0-liner, if I’m right.
Just like in the Go To days, or the days of manual memory management, we are turning into glorified accountants. Check every code path for the proper state to be properly reset, updated, disposed, released.
In this case, only go and clojure are true 0-liners, as you still need the await keyword in C# (and let! etc in F#) to indicate a blocking call.
When I announced Habits 2.0, a fellow Western MA Hackathoner, Molly McLeod, reminded me of BJ Fogg and his Tiny Habits method.
Only three things will change behavior in the long term.
Option A. Have an epiphany
Option B. Change your environment (what surrounds you)
Option C. Take baby steps
I had first learned of BJ from Ramit Sethi’s interview with him. The moment I remember most clearly was his method to start to floss. He suggested that you only commit to flossing one tooth each day — if you did that to start and internalized that that was success, you’d start flossing more eventually. I started doing this, and while I’m not a perfect flosser, I do floss most of the time. That convinced me that baby steps were a real thing. If you have any interest in this, sign up for a (free) week-long tiny habits session with BJ.
So, with Habits 2.0 out the door, I am going to plan 2.01, a baby step improvement of 2.0 by just doing a very small amount of work each day on it. I joined BJ’s tiny habits for this week and he recommends adding a 30-second behavior triggered by something you will definitely do each day. I decided that once I put my dinner plate in the dishwasher, I will sit at my desk and run the Simulator. Then, I will celebrate that as a success (and mark it done in Habits, of course).
I have been doing that for about 6 days, and each day when I run the simulator, I usually test Habits out a little, and write up a Trello card or write a small test. BJ’s advice is to keep it completely pain-free and small and to not worry about building on the tiny behavior. Still, in this time I have managed to make a bunch of small improvements to Habits, which I look forward to sharing soon.
Jobs-to-be-done (JTBD) is a theory for what causes us to buy things. The quick description is: jobs arise in our lives and then we hire products or services to do them. The key insight is that the job attributes should be used to guide product development, not the customer attributes. Here is Clay Christensen describing the concept if you haven’t heard it before.
I was lucky enough to participate in some training with Bob and Chris, and so I often think of Jobs theory whenever I wonder why people do anything, and recently I’ve been thinking about recruiting (yes, Atalasoft has a job opening for a software developer in our marketing department to help evangelize our products).
Now, when hiring we naturally think of the job we need done, and of course, we are explicit about that when writing the ad, evaluating resumes, interviewing, ultimately hiring someone. The job has hiring criteria and we use it.
But, at the same time, potential applicants also have a job-to-be-done in their lives, and they are judging us with hiring criteria. In this case, we usually fall all apart. We try to write job descriptions that sell ourselves too, but, frankly, I’m not sure they actually address the applicant’s criteria.
In their workshops, Bob and Chris teach how to find out why people switch from one product to another by interviewing people that have done it already. How many of us have interviewed our recent hires to find out why they switched from their old job to ours, how they found out about it, what happened in their lives to cause them to want to switch jobs? If we did that, I think we’d find that we’re advertising in the wrong places, not emphasizing the right strengths, and generally not making the applicants know that we meet their hiring criteria.
I’m sorry to say that I haven’t done this, so I don’t really know what needs to change.
In any case, I’m going to be thinking and posting more about this — hopefully trying it in practice. In the meantime, if you are a web programmer (preferably in .NET or Java), have at least 5 years of experience, and you want to work in a developer tools company’s marketing department, creating technical content (demos, blogs, articles, sample code, tutorials, brochures, etc) to help developers learn more about our products, get in touch with me. At Atalasoft, you’ll work with smart and hard-working colleagues, where we have an enormous amount of respect and trust in each other. Some of the best programmers in Western MA have chosen to work here, and we can’t wait to meet you.
Back in 2008, I made a simple iPhone app called Habits to help me remember to do some recurring tasks that were not a regular schedule. I made a few updates early on, but it basically did what I needed it to do, so it’s been a while since I have looked at it.
A couple of weeks ago, I decided to refresh its look in anticipation of iOS 7. Unfortunately, an app compiled with iOS 6 doesn’t automatically pick up the new look — at the very least, you need to recompile. Instead, I decided to design something custom that would look good now and feel at home on iOS 7. While I was at it, I updated the icon using the iOS 7 app icon grid.
You should absolutely be using ARC in your iOS projects, and if the project predates ARC, go ahead and use the refactoring tool to get it to ARC. It really doesn’t take long and you’ll end up with a more stable app that will be easier to maintain.
That being said, you can’t completely ignore memory management. You can still get EXC_BAD_ACCESS, Zombies, leaks, etc., even with ARC projects. Here are some things you should know
ARC is not garbage collection. It statically analyzes your code and then puts in release and retain calls where they are needed. It’s still susceptible to a retain-cycle — two objects with references to each other. You can still have references to dead objects.
If you have a retain-cycle, a common way to deal with that is to make one of the properties weak (which you should probably do), but now that reference is susceptible to becoming a Zombie. A weak property will not call retain on the object, so when the object is deallocated, it would then refer to a dead object. If you have weak properties and get EXC_BAD_ACCESS, go reproduce it under the Zombie instrument.
Under ARC, you cannot use autorelease any more, but the calls into non-ARC libraries can (and do, especially iOS frameworks). This means that you sometimes need to use your own autorelease pool. Under ARC, use the @autoreleasepool keyword to wrap areas where autoreleased objects are created that you need released before you return back to the thread’s main pool. If you see leaks of objects in Instruments that you don’t alloc or hold onto, and use threads, add in @autoreleasepool blocks.
Don’t use non-ARC code in your project by copying the source in. Build them in their own Xcode projects and then use the resulting .framework or .a in your project. It’s likely you wouldn’t be able to anyway, but just in case. (if you happen to be MRC — then really don’t copy ARC source into your projects — this will usually be compilable code, but will leak like crazy)
Test your code under the Zombie and Leaks instruments — especially if you use bridging, weak references, or are in any way managing retain-cycles (breaking them yourself without weak).