Generate beautiful code documentation with a simple shortcut using AppleDoc, Xcode custom behaviors and AppleScript!

This time I realized something really great and I’m truly satisfied about it!
Few days ago I discovered a fantastic open source project from GentleBytes called AppleDoc by reading a post on Cocoanetics.
This is a tool that generate an Apple-like HTML documentation from source files (by using the proper comment style) and it also generates installable docsets and Atom feeds for the download from a remote host.
After a couple of tests and document generations my big question was: “how can I automatize the process without launching a script every time and for each project I want to document?”.
The first obvious answer was “add a Run Script in the build phases!”… but it’s not a smart idea to launch a similar long script for every build, because it takes several seconds and potentially minutes depending on the amount of classes to analyze, and it’s often unnecessary to update a documentation if method signatures remain the same. So I searched for an alternative way to execute scripts from Xcode only when desired, by focusing my efforts on its “Behaviors” (Xcode > Behaviors > Edit Behaviors > +). Behaviors can be triggered by events (only default behaviors), using menu or with a custom shortcut and a behavior can perform several actions like running a script…
and here I started to waste a lot of time in order to realize what I had in mind (create a single auto-runnable script to generate code documentation for each project without hard-coding paths and names), because the environment variables I was using in Xcode build phases as a test can’t be used in external scripts (since they are not attached to the Xcode process as far I understood).
So the problem was: “how can I retrieve this variables dynamically from our beloved ide? is it possible?”… it’s been an hard google search plus a couple of questions asked on StackOverflow (Did I tell you how much I love that site? I really love it!) in order to clear my dubs… and yes, it’s possible thanks to AppleScript! Xcode exposes several objects that can be queried by this funny script language, so in this way I first realized an AppleScript to retrieve the variables I need (project name, project path and company) and then I invoked my old and refactored bash script passing them.
In conclusion I’m now able to launch document generation for each project I’m working on, by simply press ALT+CMD+D (a custom shortcut of my choice), I also configured a submarine sound effect and the display of a bezel alert… really wonderful!

This is the AppleScript used for the behavior that invoke the bash script by sending it the necessary arguments:

#!/usr/bin/osascript

tell application "Xcode"
	tell first project
		
		-- variables to export
		set projectName to (get name)
		set projectDir to (get project directory)
		set company to (get organization name)

		-- invoke script passing extracted variables
		do shell script ("sh /PATH_TO_SCRIPT/appledoc.generate.sh " & projectName & " " & projectDir & " " & company)
		
	end tell
end tell

Of course you have to replace “/PATH_TO_SCRIPT/appledoc.generate.sh” according to your path.
If you decide to create your own AppleScript script using the default editor (/Applications/Utilities/Apple Script Editor), remember to save it as a plain text and to include the proper header declaration (#!/usr/bin/osascript), otherwise Xcode will throw an exception trying to run it!

…and this is Sparta the bash (I added a couple of say commands in order to debug the process… remove comments to hear your mac speak!):

#! /bin/sh

# Input arguments: 
# $1 -> project name
# $2 -> project path
# $3 -> company name

# dynamic variables
docsURL="http://www.$3.com/docs";
projectsPath="$2/../";
docsPath="${projectsPath}/AppleDocOutput";

#say "project is: $1";
#say "path is: $2";
#say "company is: $3";
#say "project path is: ${projectsPath}";

# create AppleDocOutput folder if not exists
if [ ! -d $docsPath ];
then
	#say "create output folder";
	mkdir "${docsPath}";
fi

#say "run appledoc";

#invoke appledoc passing computed arguments
/usr/bin/appledoc \
--project-name "$1" \
--output "${docsPath}/$1/" \
--docset-feed-url "${docsURL}/%DOCSETATOMFILENAME" \
--docset-package-url "${docsURL}/%DOCSETPACKAGEFILENAME" \
--docset-fallback-url "${docsURL}/$1Doc/" \
--ignore "$1Tests" \
"$2" > "${docsPath}/AppleDoc.log"

the bash invokes AppleDoc by assuming its location on /usr/bin/appledoc, the arguments passed are few since I use the GlobalSettings.plist for the main setting and I override only certain options (read GentleBytes reference for more info).
I also redirect the output of the command to a log file for an easy debug.
Remember to make both scripts executable (chmod +x) in order to use them!

…that’s all! If you want more info leave a comment (it’s free)

Xcode key bindings: how to create a custom shortcut to convert upper case text to lower case and viceversa

Since one of the most visited post on my blog is that one about case conversion in Eclipse, I decided to share how to implement 2 custom shortcuts to do the same in Xcode.
In “Preferences” panel, there is a tab called “Key Bindings“, here we can configure keys used for shortcuts. By default the most are already configured, but that’s not the case for text case conversion. By typing “case” to filter the long list, you can see 2 commands: “Lowercase word” and “Uppercase word“, all you have to do is to click on the “key” column and register your shortcut.
To avoid conflicts and to make them simple to remember I did choose “SHIFT + CTRL + L” for the first and “SHIFT + CTRL + U” for the second (but you can register your own one).

My migration to ARC (Automatic Reference Counting), using Xcode 4.2 refactor assistant

Starting from Xcode 4.2 and the introduction of the new LLMV compiler, is now possible to use “Automatic Reference Counting” (ARC). This powerful feature frees developers from memory management by eliminating the need of sending release and autorelease messages. Anyway this is very different from a garbage collector, in that it’s a compile-time feature, which basically analyze the code and automatically inserts that calls when necessary for us. In this way we have the best of two worlds: we don’t have to worry about releasing, deallocations and memory leaks, but simultaneously we have the performance of a memory managed language. This is very cool, however I don’t envy new upcoming iOS developers whose will start directly using ARC. It’s very important learning and understanding how memory management works in Objective c, and the difference between owning a reference to an object or not (I recommend this reading). For example I fear that new developers won’t understand the use and benefits of NSAutoreleasePool (that have been replaced with @autorelease block in ARC).
Anyway in the last days I switched my code to ARC using Xcode refactor system and I want to share my experience.
These are the steps I followed:

1. “Preferences” -> “General” -> check “continue building after error”

This step is fundamental to avoid an huge waste of time repeating the next steps every time an error is encountered!

2. “Edit” -> “Refactor” -> “Convert to Objective-C ARC”

3. “Select targets to convert” (check them)

4. Click “precheck”

5. “Cannot Convert to Objective-C ARC” (Xcode found N issues that prevent conversion from proceeding. Fix all ARC readiness issues and try again.)

You will see this message at least once, because your code contains calls that are forbidden by ARC.

6. Fix them using suggestions (click on errors to open the popup containing the tip). Then repeat from step 1

7. “Convert to automatic reference counting” window will appear (once issues have been fixed)

8. Click next

9. Review automatic changes

10. Save

If after clicking on “save” nothing happens, you may be unlucky as I am and Xcode is unable to prooced because it silently fails trying to generate a snapshot of your project. I solved the problem by doing a clean install, that means run “sudo /Developer/Library/uninstall-devtools” to remove all files and install Xcode from the scratch (by the way this had also improved its performances).

The migration was pretty painless in my case, however I had to disable ARC on certain files because it was very hard to refactor the code in order to make it ARC-friendly (this is the case for heavy use of Core Foundation functions).
To disable ARC in these files I added the flag “-fno-objc-arc” in the column “compiler flags” under “Build phases” tab (related to my target).
I then did a small refactor by marking NSError pointer as “autoreleasing”:

NSError *__autoreleasing error = nil;

This is in fact a little optimization trick, that avoid the creation of an extra temporary variable by the compiler. (read more here).

I also marked all readonly properties as “strong” and removed the “__unsafe_unretained” placed by Xcode.

…that’s all folks… all works pretty well, the code is shorten and cleaner and I’m satisfied :)

Display full string’s content while debugging in Xcode 4

I spent several time playing with Xcode 4 trying to figure out how to display the full content of a couple of strings during a debugging session. It seems that text displayed in the “variables view” panel are limited to 100 characters, if a string is longer than that size it will be truncated to the first 97 characters and will be added suspension points (…).
To inspect the full content of the string, we have to right click on the desired variable and choose “print description“, at this point xcode will print it to the console (fundamentally is like if we had written an NSLog() in our code at runtime)

Handle complex iOS projects with multiple dependencies

If you are reading this post I’m assuming you are having an hard time and tons of errors from xcode trying to compile third party libraries into your project.
I had my hard time me too! I wrote this little “tutorial” after a whole day of build failures, warnings, tests, google searches, configurations, git clone, svn checkout… and a lot of stress! I hope I will help you saving time and reach your goals, good reading ;)

To include a third party library into our iOS projects there are fundamentally 2 ways. The first, and the simplest, is to include the raw sources (headers and implementation files) into them (using drag and drop or “add files to” from the contextual menu), once done we are ready to go after a simple build. Anyway this is not an ideal solution, because in a scenario in which we have several projects all requiring a particular library, we should copy/paste its sources for each project and moreover we should update library’s sources manually every time it will get updated (in the git/svn repository by the “vendor”)!
The second and the best way, is to manage libraries we will depend on, as sub-projects and linking against them. Here is a brief to-do-list:

What to do

1. Each dependecy should be an xcode static library project, that is an .xcodeproj with a target of type library (“.a“) rather than application (“.app“). In most cases third party libraries are already configured in this way and ready to be imported (step 2)

2. Each project must be added as a sub-project to the main project. You can do this by selecting the main node in the folder tree (that one with the blue icon reporting project’s name) and adding the .xcodeproj file using “add files to...” from the contextual menu (DON’T CHECK “Copy items into destination…” because we are going to create a reference to it not a copy of it!)

3. All the static libraries must be linked to the main project: go to the Target’s “Build Phases” and add the library (.a) in “link binary with libraries

4. The main project should specify all the paths where subprojects headers are located (“header search paths” in Target’s Build Settings).

An absolute path is the best way to speciy this paths, in my case: “/Users/davidezanotti/Documents/X_CODE/CoolLibrary”

IMPORTANT:

If the headers are located under different subfolders (ie: /CoolLibraryPath/headerFolder1/, /CoolLibraryPath/headerFolder2/…)
you can specify just “/projectPath” and check “recursive” to automatically scan each subfolders for .h files, otherwise if they are in a specific folder like “/CoolLibraryPath/src/Classes/” and you don’t want a recursive search, be sure the path string ends with “/”

5. If a project we are referencing to, makes use of particular frameworks (UIKit.framework, SystemConfiguration.framework, Security.framework…), the main project must use these frameworks too. So we have to include them in Target’s “Build Phases” (under “link binary with libraries“)

How to prevent errors:

1. The main project should specify the following flags “-ObjC -all_load” in “Other linker flags” (under Target’s Build Settings). These force the loading of all headers and categories.

2. All subproject should expose their header files as “public”

3. Read CAREFULLY (word by word) instructions that come with downloaded libraries and ensure you did exactly what they say

4. Check CAREFULLY each path typed

5. Pay attention to typo errors

What to do when build fails:

It depends on what type of error(s) has occurred, anyway in 99,9% read again “What to do” and “How to prevent errors” until you will compile. Don’t be fooled by the error message, because it’s often inaccurate and misleading. For example a message like “undefined symbol for architecture i386” may tempt you play with architectures settings when the problem is completely different.
If after several attempts you are still unable to compile the project with its dependencies and you are unable to find the answers on google, try to create a new project from the scratch, add your original classes and assets and then add libraries one at time.

ps. In some case I had to change some import from to “Foo.h” to compile all the projects successfully

Special case: JSON framework

This framework (available here: https://github.com/stig/json-framework/) is used by several libraries, that unfortunately had adopted it by simply copy the sources into the project (first way). The result is that I was unable to compile my project because I get “duplicated symbol” errors because I’m using a couple of them. To solve my issues I cloned the original git repository, added that project into mine and under Target’s “Compile Sources” section of these libraries I removed .h and .m files of the JSON framework. The final result is that I left untouched the downloaded libraries (the files are still where they were), but I can compile without problems because now I don’t have duplicates, all the sources are retrieved from the JSON project once rather than one time for each sources in the library!