Xcode is, for the most part, a fine IDE. But there are many things lacking. If you compare with Eclipse, for example, one of the big lacking aspects is refactoring.
Specific example: renaming a class is incredibly painful in Xcode. In Eclipse, you can rename a class and the file will be renamed, all the declarations will be modified, and all the uses of the class will be changed automatically. In Xcode, you have to do this by hand. This is even worse if you have used some of your classes in Interface Builder: some of the files it creates are binary, so things cannot be easily replaced there.
Recently, I had to some some major class renaming in Xcode, and here are my notes about it, in case anyone finds them useful.
The problem occurred while working in CopperExport. It is heavily based in FlickrExport, so many of the classes are duplicated. Two plugins in iPhoto cannot have classes with the same name (only one of them will get loaded), so I had to rename all the common classes.
For the Objective-C and Xcode project files, it’s easy because they are all text files. Here’s what I did:
1. Open your project in Xcode, and select “Clean all targets” from the “Build” menu.
1. Quit Xcode.
2. Make a full copy of your project directory, just in case.
3. In a terminal window, change into your project directory.
4. For each class to rename:
mv OldClass.m NewClass.m
mv OldClass.h NewClass.h
perl -p -i.bak -e ’s/OldClass/NewClass/g’ `grep -r OldClass .`
(the quotes surrounding the grep command are back ticks)
A few comments:
* The last command is doing textual substitution on all the files that contain the string “OldClass”. So make sure that the string does not appear somewhere you don’t want to make the change. In particular, if the string is part of some other class or variable name that you do not want to rename, you will have problems.
* The perl command will leave the old version of each file on a file with the same name plus the extension “.bak”. You can use the diff command to see what changed, to make sure nothing unexpected got changed. For example:
diff ChangedFile.m.bak ChangedFile.m
You could also use the FileMerge application (from /Developer/Applications/Utilities) to show the differences in a prettier format.
* It will also rename the class in the project file (.xcode), so when you reopen the project in Xcode, you should see the file with its new name.
* Beware of binary files! One of the files produced by Interface Builder, `keyedobjects.nib`, is binary, and if you have used any of the classes you want to rename (for example, to link them into your interface), their names will probably be there. In this case, you can use the technique described above only if the two class names are of the same length. If this is the case, things will work fine (I did this several times).
* In any case, always make copies of the files before you modify them, and compare the files before and after each change, to look for unexpected substitutions.
That’s it. It’s quite pedestrian, and I’m sure there’s a more intelligent way of substituting things in the IB `keyedobjects.nib` file, but for my limited needs, this worked quite well. Maybe Xcode 2.0 will have better refactoring support? I couldn’t find it here, but who knows.
1 response so far ↓
1 Mark H-J // May 6, 2005 at 5:54 pm
keyedobjects.nib appears to be a binary plist file, so you can convert it to an XML plist using:
plutil -convert xml1 keyedobjects.nib
(It converts in place though, so I guess it’s sensible to back the file up first).