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 appeared on an episode of The App Guy podcast that aired yesterday (12/27).
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 #1 above causes you not to be able to build, then use Apple’s Provisioning Troubleshooting guide.
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.
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.
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 can see some screen shots on the Habits documentation page, and if you want to buy it, Habits is 99 cents on the App Store.
Here’s a full list of everything that I had to do for 2.0 in case you’re a developer with an older app and want to see what you might be in for.
- Converted to an ARC app
- Moved lots of properties to auto-synthesize
- Updated deprecated APIs to iOS 6.0 versions
- Skinned the tables, mostly with custom cells
- Added a pan gesture to the front-page cells (try moving them to the left for a short-cut)
- Supported local notifications and badges (requiring a new settings page)
- Made a new icon
- Updated my Google Toolkit unit testing to Xcode built-in unit testing (which was gratefully, very easy) — the main issue is dealing with unit-testing’s idea of the document folder
- Updated all button and default images
- Updated in-app help
- Converted my svn repository to git
- Added database migration to support the settings (this app uses sqlite API directly)
- Refactored a lot of code, mostly in the database, view controllers and custom cells, to share more code.
- Fixed a bug in the calendar to support iPhone 5 size better.
- Updated App Store listing, web page, made this post, etc.
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).
- It’s rare, but I ran into a bug in the iOS framework that didn’t retain Storyboard created Gestures correctly in a tabbed-app. It was my first big ARC project, and it didn’t even occur to me to check for Zombies, but that would have pin-pointed the issue right away. Rule of thumb, the underlying code is still normal retain/release/autorelease based — debug it the same way you would have with Manual Reference Counting.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
If you read XKCD on an iPhone and iPad, there’s no way to see the tooltip text on the comic (usually the funniest part).
Here’s a bookmarklet to pop-up the XKCD tooltip.
Here’s the process for adding it your iPhone
- Go to this blog-entry on your iPhone
- Select and Copy the bookmarklet above
- Go to XKCD, bookmark it, and save the bookmark
- Edit the bookmark, change the Title to “XKCD Tooltip”
- Paste the bookmarklet to the URL of the bookmark
To use it
- Go to XKCD,
- Choose the bookmarklet from your bookmarks — it will popup the tooltip
Starting with Habits 1.1, I started incorporating static analysis into my build. In my previous experience with things like Lint and FXCop — I had found the signal to noise ratio to be too low to be useful. It’s hard to believe, but scan-build is 100% signal — every single issue it flagged was legitimate and needed to be fixed. Now, keeping Habits free from issues is easy, since I only have to deal with one or two at a time.
There were a couple of times I thought it was leading me in the wrong direction, but it was right so often that I just trusted it, and it was right about those too. I had a particularly interesting case with a custom table cell, where I wasn’t releasing properly, and causing a crash when I dealloced the window. Scan-build helped me make sure I found that before release.
I thought Java was bad. Took me a while to figure this out and googling didn’t help, so I am just putting this out there for the next person who needs this.
To get the number of days in a month:
+ (NSInteger) getDaysInMonth:(NSDate*)date
NSCalendar * cal = [NSCalendar currentCalendar];
return [cal rangeOfUnit:NSDayCalendarUnit
There’s a great thread by an iPhone developer on Reddit.
Yay! It took several months but as of today I was able to search for my app and I saw it listed inside the app store. Now you may be saying “so what”, but if you have ever looked into the steps that this takes, you know it’s something to celebrate.My app is a very simple game, but I think I’ve learned enough during this process to distill some important lessons that may help you if this is something you’ve been wanting to do…
I wrote a similar post when I finally finished my iPhone App.