Making Xcode's Build and Analyze much better
On the Clang analyzer site, they have instructions for setting up the latest analyzer so that Xcode would use it. Unfortunately, the settings that find some very common problems are off by default. Here are instructions for getting the Clang analyzer to run with those options on.
To make sure you are doing it right, make your project completely succeed a Build and Analyze, then comment out a release that you are doing in any dealloc. Rerun Build and Analyze -- it should not find this problem.
Then,
1. If you don’t have it, download and untar the latest checker
2. Make a script file called full-analyze-clang and put it in the checker’s bin directory, with this code
#!/bin/bash CLANG="`dirname $0`/clang" CLANG_CMD="\"$CLANG\" -Xanalyzer -analyzer-check-objc-missing-dealloc -Xanalyzer -analyzer-check-objc-missing-dealloc -Xanalyzer -analyzer-experimental-internal-checks $*" eval $CLANG_CMD
3. From the Terminal, run this command to make the script executable
chmod +x full-analyze-clang
4. In the checker root directory, there is a script called set-xcode-analyzer. Run it like this:
sudo ./set-xcode-analyzer --use-checker-build=FULL_PATH_TO_CHECKER/bin/full-analyze-clang
5. To test, Run the Build and Analyze on the project you set up with the bad dealloc. If it finds 0 errors, this could be because something is wrong with the way the script is set up.
Important parts if this stops working with a future clang:
The set-xcode-analyzer expects a directory or a full-path to clang. It checks to see it has a full-path by looking for a path ending with “clang”, which works for us because our script’s name ends in “clang”. If they change this script in the future, this might not work
Build and Analyze just reports a successful build if our script reports errors -- it’s just looking for the existence of result files. You might need to add logging lines to the script to figure out what’s going on. Log to a full-path because the current directory is inside Xcode’s path somewhere when the script is run.
Use something like this as your last line to debug:
eval $CLANG_CMD > `dirname $0`/cl.out 2> `dirname $0`/cl.err
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
Xcode 4
- It runs side-by-side on the same machine as Xcode 3.2
- It uses the exact same project file format
My first impressions after an hour or so:
Putting the view in Assistant mode (Opt-Cmd-Enter) is really nice. Shows the .m when editing the .h and vice versa. When editing an .xib file, it shows the ViewController.
Keeping the Interface Builder dialogs organized as parts of a single window is also a big win. It’s confusing having them as free dialogs. Specifically, having the parts of the main dialog (File’s Owner, First Responder, View, etc) as just part of the chrome (and always visible) is nice.
I think I’ll really like the Log Navigator -- especially for debugging. I am constantly clearing the console, but this saves each one in a separate view so I can keep them around.
The Project Navigator is so much cleaner (replaces the Groups and Files tree). It always felt like Xcode just stuffed everything there instead of organizing it elsewhere in the GUI. However, it took me a long time to figure out where Build Settings were (click the project name in the Project Navigator), but it seems obvious now.
Build and Analyze still doesn’t find dealloc omissions of retained property releases. I would like the default to be set to finding these.
Some keyboard shortcut changes. The GUI is so radically different, so this is excusable. For the most part, things are the same.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
LGPL and the iPhone
To achieve this, the LGPL gives you a few options for compliance. I am not a lawyer, but I believe that all of them are incompatible with iPhone apps delivered legally through the AppStore. I will lay out my reasoning here:
Section 4d gives two options for compliance: Either provide the source or object files suitable for relinking (4d0) or use a shared library (4d1).
Shared libraries are out, because Apple does not permit their use in the AppStore.
Section 4d0 is a little more complicated. For an application targeted to a PC or Mac, it would be easy to comply by just packaging up your .o files, the LGPL library, a makefile, and documentation. However there are subclauses in section 4 that make me believe that there is no way to comply on the iPhone. Specifically:
Section 4d0 not only specifies that you must convey the minimal source and object files, but you must also provide terms. Together they must “permit the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work”
Section 4e requires that you provide instructions that allows some to change the LGPL portions, create a new combined work and install and execute that combined work.
To do either of these things, the user would need to be enrolled in Apple’s developer program which costs $99/year. These terms are implicitly part of your terms, meaning that it’s basically equivalent to you charging $99/year for the user to make modifications.
The GPL allows you to charge what you want to convey the Combined Work to begin with, but section 10 of the GPL (which I think still applies to the LGPL) states:
Now, obviously, being able to develop isn’t free, but those costs are not as directly related to exercising your rights as the $99/year is. Specifically, you cannot create an executable or put in on a device without the certificates you obtain from the program.You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License.
Here’s an alternative view from Huy Zing -- I think the “Spirit of the LPGL” section in the blog is actually required by the text of the license.
Here’s a discussion on the cocos2d forum about switching away from LGPL. They tried adding to the license at first and then moved to an MIT license.
I haven’t been able to find any official ruling on gnu.org, so I will write them and see if they can add to their FAQ (as they did for Java when it was an issue).
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
Understanding EXC_BAD_ACCESS
The description here is a high-level way of thinking about it. The details are quite a bit more complicated, so I’m simplifying it.
On the iPhone (and most modern OS’s), your application is given memory as you need it. The memory is given in chunks that are bigger than your request, and then the unused parts are parceled out over the next few requests.
When you deallocate an object, that chunk can’t be returned to the OS right away. It has to wait until all of the memory in the chunk is deallocated.
Inside all of this memory is a complex data structure that is maintained by the alloc and dealloc messages to organize how each part of the allocated memory is being used. The pointers you hold are just part of that datastructure (where the object is), there are other parts that are only used by the allocator.
What EXC_BAD_ACCESS is saying is that you did something that caused a pointer (yours, one internal to the iPhone, or one that the allocator is using) to be dereferenced and that memory location isn’t inside one of the chunks assigned to your program.
This could be because
- The pointer used to point to memory that was ok, but its chunk was deallocated.
- The pointer is corrupt.
Your goal in debugging this is to make the problem line of code be flagged by either the compiler or debugger.
If you do that, then fixing it becomes a lot easier.
Of the two possible problems, #1 is far easier to find. It’s almost definitely because you didn’t use retain/release correctly and there where either too many releases or too few retains.
Do this:
- Run Build and Analyze. Make sure you fix or understand every single error it flags. I personally have 0 Build and Analyze errors in every project I have and I go out of my way to keep it that way. If I ever get a false positive, I figure out how to make Build and Analyze understand what is going on, so that it doesn’t flag it.
- Run scan-build with all checks on. This isn’t built in, so if you’re in a hurry, skip this for now. scan-build is the project that Build and Analyze is based on. It can be run with much more thorough settings.
- Set up Xcode so that it never deallocates. Instead, it turns objects into Zombies that complain if they are used. See Tip #1 on this post for instructions.
For #2, your task is harder. If a pointer is corrupt, there are lots of possible reasons
- The pointer could have never been initialized.
- The pointer could have been accidentally written over because you overstepped the bounds of an array
- The pointer could be part of an object that was casted incorrectly, and then written to
- Any of the above could have corrupted a different pointer that now points at or near this pointer, and using that one corrupts this one (and so on)
If this is the situation you are in, then these are the things that will help
- Enable Guard Malloc (Tip #2) - this makes the datastructure that represents the allocations much more sensitive to corruption. You need to use the enhanced features of the debugger to get anything out of it (explained in the tip).
- The line of code that triggers the crash is a clue to what pointer is corrupt. If you move it around it might be able to help you narrow down the point of corruption.
- If all else fails and you are desperate, try Valgrind.
Once one of these methods gives you a different problem (either a warning or another EXC_BAD_ACCESS), don’t worry that it seems completely unrelated to your original problem -- that’s a common problem with corruption.
Also, random changes to your program may make this problem “go away” -- it’s not really fixed, though. Your corruption or early deallocation is still there, but it’s not triggering an EXC_BAD_ACCESS. Its effects could be far worse, however, so it’s a good idea to try to keep reproducing it until you are sure you addressed the problem.
Things to remember
- Corrupting a pointer doesn’t immediately trigger EXC_BAD_ACCESS. Neither does using a corrupted pointer unless it’s specifically now pointing to memory that isn’t mapped to your application.
- Deallocating an object doesn’t immediately release the memory to the operating system -- only when the chunk is unused, can it be returned.
- The line of code that is triggering the EXC_BAD_ACCESS might not be the problem. It can be a good clue, but don’t assume the problem is this code.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
How to Debug an iPhone App Crash, Part 1: EXC_BAD_ACCESS
This post is for how to debug crashes that show that the app received the signal EXC_BAD_ACCESS in the console. If you have this, the most likely thing that you are doing is sending a message to a released object. Another possibility is if you are using C/C++ allocations (or a library that uses it) and are overrunning memory or using freed memory.
Update: I explain this much better in a follow-up to this blog
Here are a few ways to debug that:
- Run Build and Analyze: This kind of Build is very good at finding retain/release bugs. Take a good look at everything it flags.
- Even better, run scan-build. I did a test recently, and found that some common errors are off by default in Build and Analyze that can be turned on in scan-build.
- Choose Run > Enable Guard Malloc in the menu, and then re-run your application. This finds a whole class of buffer overrun issues. If this detects it, you’ll see a better error in the console. Read this to see how to use Guard Malloc once it’s enabled.
- You can instruct the compiler to ignore release calls and then report if anyone is sending messages to objects that would have been deallocated. This results in much better errors in the Console if it detects them.
- Valgrind is the gold standard for finding memory bugs on Linux, and here’s a way to get it working in the iPhone Simulator.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
scan-build finds things Build and Analyze does not
There is one kind of bug that scan-build was very good at finding -- forgetting to set retained properties to nil in dealloc isn’t found by default in Build and Analyze. It’s not even part of the default scan-build any more (not sure why -- it was great).
Anyway, I recommend using scan-build directly instead of Build and Analyze. Here’s how:
- Download scan-build
- Just unpack it into any directory and add that directory to your PATH
- Open a Terminal and cd to your project’s root directory
- Run scan-build and view results
Here is a scan-build line that works for iOS 4.0:
scan-build -analyzer-check-objc-missing-dealloc -analyzer-check-llvm-conventions --experimental-checks -k -V -o scan-reports xcodebuild -configuration Debug -sdk iphonesimulator4.0 clean build
I’ve turned on all checks, and now it catches if you forget to set properties to nil in dealloc.
Run Build and Analyze often in Xcode, but every once and a while, run a full scan-build with the latest version as it finds problems that the Xcode version will not.
UPDATE: Instructions on getting this working in Xcode from the Build and Analyze menu
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
Static Code Analysis for iPhone Apps
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.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
Cocoa date functions are crazy
To get the number of days in a month:
+ (NSInteger) getDaysInMonth:(NSDate*)date
{
NSCalendar * cal = [NSCalendar currentCalendar];
return [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:date].length;
}
Reddit thread on iPhone Development
I wrote a similar post when I finally finished my iPhone App.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...
New iPhone Blog
Start Habits not Resolutions
- Lose Weight
- Get Your Finances in Order
- Go Greener
- Curb Your Vices
- Get in Shape
- Relax More
- Pursue a New Career
- Upgrade Your Technology
- Organize and Optimize
- Start a New Hobby
The main reason that I have had a problem with a resolution is that I don't really think about them much a week or so after New Year's. A few years ago, I created a small web app for myself to log how well I was doing at keeping to resolutions I was making. A few months ago, I ported it to the iPhone as Habits.
Instead of making resolutions this year, I created a few habits instead. I want to lose some weight this year (the #1 resolution), so I added a habit to run every 2-3 days, to do bicep/chest and shoulder/tricep weight training once a week. I want to keep my house in better order, so I added a habit to clean up and to process my mail pile more regularly.
A lot of these resolutions should just be a recurring task that you try to do as often as possible.
Habits reviewed in Macworld
Habits by Louis Franco helps users form good habits, which sounds simple enough. But developing habits requires a bit of time and discipline. It requires repetition and awareness. Habits keeps your calendar free from clutter associated with routine tasks or the general stuff of life.
Habits on Sale for $0.99 until the end of January
I am working on version 1.1, and I will post it at the end of January and return it to its old price. Until then, here's hoping that you're able to turn your resolutions into habits.
(The AppStore takes time to fully update -- please make sure it says that the price is $0.99 before you buy)
Buy Habits on the App Store
O'Reilly's iPhone AppStore Answers
The other major improvement is dropping the NDA for released SDK's, thus opening up the possibility of books, online tutorials and blogging about iPhone development.Changes have been relatively slow to come to the App Store. However, with the addition of review copies, as well as limiting ratings to those who've purchased applications, Apple has made changes that have been welcomed by developers. I'm hopeful that the App Store will continue to improve over time and address additional issues.
More interesting iPhone pricing articles
And, here's another iPhone app pricing article I got from John Gruber's DaringFireball. In the article, Peter Cooper uses popularity as a stand-in for units sold and and tries to figure out which apps have the most revenue. Put this one in your RSS feed if you are interested in hearing more as this installment covers mostly the Games category.Having more than doubled over the last two months, Gaming remains the largest category accounting for a quarter of all apps. The fastest growing categories were Education and Lifestyle. Medical is the newest app category and as of the end of November there were over 80 medical apps, the 10 most popular of which were free. Among Game apps, Racing, Music, and Sports were the fastest growing Game sub categories.
Seth Godin's iPhone App Ideas
The Google Maps app on the iPhone has traffic data already--what's missing is that I don't think it takes that into account when selecting a route, or updates it if conditions change. If the traffic data is available with an API (like most google data), then this might be easier than even Seth thinks (no server side) -- of course, no lock-in either.Have the iPhone use the gps data... upload where I was a minute ago and where I am now. Figure out my speed and route. Use the data to tell other RadaR users which route is best. It's worth $20 a month if you live in a place with traffic jams. It's a natural monopoly--once someone figures it out, why wouldn't everyone want to use the market leader?
The second idea needs some kind of server-side dialier because Apple doesn't let apps run in the background:
Here's an easier one that you could probably sell as well. I type in a phone number and enter a time. Record a message and press go. I can cue up a bunch of messages that are based on time. I can have groups get the message I record, at the time I want them to get it.
Interesting iPhone App Pricing Articles
This other article from Andy is also good.The fix for pricing too low is really simple: raise your prices. Most $0.99 apps should become $9.99, $4.99 apps should become $14.99, and so on. With a $9.99 app, you’d make $7 per copy and at 16 copies per day, you’d make about $40,000/year. That’s not a great income, but that could potentially support one iPhone product being developed in some Iowan’s wheat field.
John Gruber made an interesting point when he linked to Andy (software with higher prices needs demos and refunds)
Tap, Tap, Tap has had a couple of AppStore hits, so what they have to say is also very interesting.
iPhone apps are typically much smaller and more focused than desktop apps and as such, should be priced accordingly. In addition, you need to take into account the much larger market that you’re dealing with here… Apple is selling well over 10,000 iPhones per day and these are all potential new customers, plus all the existing iPhone owners and iPod touch sales.
Unit testing on the iPhone
One quirk -- it instructs you to add a build step that runs the unit-tests during build time and shows the failures as compiler errors that you can then use XCode to track down. That's nice, but I have found that you don't really have enough of an environment to successfully run every kind of test -- they run fine if you run them in the simulator. The main problem I have is with setting up my database in my Documents folder -- I get errors at build-time that work just fine at run-time.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
How I use Habits

Generally, I use Habits to help with Sharpen the Saw type of tasks -- things I want to make sure I do every once in a while, but not necessarily at a specific time. Also, unlike a recurring event in a calendar, I can record how well I do with them (if I do them late, early, or skip them).
Debugging memory based crashes on iPhone
In Xcode, it's actually really easy to get information about how you might be managing memory incorrectly.[...] crash as early as possible. It's no fun to figure out a crash bug once the culprit function has already returned. You really want the root cause somewhere on the call stack when it's detected.
Tip 1: Set Deallocated objects to Zombies
Go to Project->Edit Active Executable, go to the Arguments tab and in the environment variables section, add
NSAutoreleaseFreedObjectCheckEnabled
NSZombieEnabled
NSDebugEnabled
And set each to YES. You can leave them there unchecked, but if you check them, then your application will now do some extra checking on autorelease and release and give you a good stack trace when you have done it wrong. A common problem is to think you need to call release when the object is already set to autorelease (see yesterday's post on what the rules are for that).
Tip 2: Enable Guard Malloc
If you think you are having an issue where you go out of bounds of a heap allocated memory block, then in the Run menu, you can check "Enable Guard Malloc". This will tell you if you overrun your bounds. It's not going to be as handy as a Page Heap style check (where each heap allocation gets its own page and therefore crashes at the point of the mistake), but it's better than nothing.
After doing this, you get more capabilities in the debugger. Read this article to see how to use them.
UPDATE: I wrote a much more detailed version of this that focuses on Understanding EXC_BAD_ACCESS.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
Managing memory in iPhone applications
When I first started Habits, I didn't really read through the entire memory management API (there were so many other APIs to read) because I have been using reference counting for a long time (old COM programmer) and the awesome leak detector included in XCode was a good enough guide to what I was doing wrong.
However, the rules are really simple, and now that I know them, I never run into memory management issues:
- Declare all of your object pointer @properties as retain unless you have a really good reason not to. Then the setter that is generated will automatically call retain when you assign. When you reassign, it knows to call release on the old value.
- In your dealloc, assign all of your @properties to nil. This has the effect of calling release on the current values if they are not already nil.
- alloc returns an object with a reference count of 1 -- so you have to balance with a release.
- If you alloc, then you should try to release in that same function. To retain the value, assign it to something that retains. Exceptions are if you are a factory function that is returning a value up to be retained by the caller.
- Obviously, each retain call needs a release.
- Built-in convenience functions return objects that are autoreleased. That means you shouldn't call release on them -- the framework will call release at some point (they are registered in an autorelease pool that that is serviced when you return back to the framework). If you created the object without an alloc/init pair, you don't need to call release unless the docs say you do (but they probably don't)
- Check all of your work with the leak detector. Also, if you crash, you're probably doing it wrong -- I will have more to say on that soon.
I highly recommend that you read Very Simple Rules for Memory Management in Cocoa on stepwise.com. Keep in mind that the suggestions for building proper setters is handled automatically if you declare your @properties correctly.
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
iPhone Development Tips
- Go enroll in the iPhone developer program before you start. Yeah, I know -- it's 99 bucks. But if you have an idea and a reasonable chance of doing it, just take the plunge. I joined after I finished, and that caused a lot of delays -- I could have been completing the other necessary steps in parallel.
- As soon as you're in, go get your application contracts going. If you want to make paid applications, you have to give Apple your tax and bank information. Again, it takes some time to get approved, so start early.
- If you don't know Objective-C -- don't worry, that's the easy part. The primer on the iPhone developer site should be good enough if you know C/C++.
- For Cocoa Touch, I recommend Erica Sadun's iPhone Developer's Cookbook. The chapter on coverflow is worth the price of the book, but everything else is there too (navigation, touch, location, contacts, etc)
- I also highly recommend iCodeBlog. Once you have some basic knowledge of the framework, check out the to-do application tutorial.
Update: just found this great flowchart of the right order to do things
Get iPhone programming tips in your inbox with my Beginner iPhone Programming Tips newsletter.
