i’m so full of ideas

Archive for the 'mac' category

Installing Xcode 3 and 4 side by side on Lion

March 19, 2012 10:59 am

Xcode 4 sucks so, so, bad. It kills my productivity like whoa. As a consequence, I’ve been doing most of my work in Xcode 3 on Snow Leopard, venturing into Xcode 4 only for testing and final releases. (I am currently working on a code library that’s used by other iOS programmers, most of whom will be using Xcode 4.)

I know I’ll have to update to Xcode 4, eventually. I can’t hold back time forever. But the longer I wait, the more likely it is that Apple will fix all the glaring issues. Until then, I’m going to cling to Xcode 3 for dear life.

Recently, Apple made things a little more difficult for me by releasing a new version of Xcode 4 that only works on Lion. So I had to update my operating system, finally. But I found a way to install both Xcode 3 and Xcode 4 side by side, without any real problems.

My new Lion setup works better than Snow Leopard did in one significant respect: Xcode 3 is now able to install and debug programs on devices running iOS 5.0 and 5.1, which didn’t work for me before. I’m assuming it’s using device debugging stuff that Xcode 4 installed, but I’m not sure. I’m just glad it works, because I use it a lot.

Here’s the steps I took, which might work for you as well.

Step 0: Remove all existing Xcode versions

I’m assuming you are starting from a fresh install of Lion, which doesn’t contain any developer tools at all. If not, the instructions given here probably won’t work. The order of installation is important.

This command should work to uninstall Xcode 3:

sudo /Developer/Library/uninstall-devtools –mode=all

And this one will uninstall Xcode 4:

sudo /Library/Developer/Shared/uninstall-devtools –mode=all

… then remove Xcode.app from your /Applications folder.

Step 1: Install Xcode 3.2.6

As of this writing, the most recent version of Xcode 3 is still available from Apple’s developer site. Download Xcode 3.2.6, which will require you to log in with your Apple dev credentials.

Alas, Xcode 3 doesn’t really want to be installed on Lion. No matter, its version checks can be defeated. I found out how to make it work from this link. I’ll repeat the instructions here, in case that link goes dead:

1. Mount the Xcode 3.2.6 DMG
2. Open Terminal
3. Enter these commands:

export COMMAND_LINE_INSTALL=1
open "/Volumes/Xcode and iOS SDK/Xcode and iOS SDK.mpkg"

… then run the installation program as usual.

Partway through, the Xcode 3 installer demanded that I shut down iTunes, even though it wasn’t running. On a hunch, I used Activity Monitor to kill iTunes Helper, and that did indeed make it shut up and finish installing.

If you want to create a link to Xcode 3, the app is installed here by default:

/Developer/Applications/Xcode.app

Drag it from that location into the Dock or wherever else you’d like it to be.

After Xcode 3 is installed, you’ll want to launch it to make sure it really works. On my system, Lion declared that it needed to download a Java runtime before this was possible.

Step 2: Install Xcode 4.3.1

Apple has decided to move Xcode 4 into the Mac App Store, so you’ll have to run the App Store app to download it. It doesn’t have an installer like earlier Xcode versions, it’s just a plain old app in your /Applications folder. Start it, and it will declare that it has to install a framework first, so let it do that.

At this point, you’ve got a cosmetic problem: the Xcode 3 and Xcode 4 icons are identical. You can solve that problem by installing Jeff LaMarche’s replacement icon. He wrote that article for a much older version of Xcode 4, but the replacement worked just fine for me.

Step 3: Install the command line tools

Xcode 4 no longer installs command-line tools by default. Assuming you need them, like I do, then you should open the Xcode 4 preferences window, go to the Downloads tab, look for the item labeled “Command Line Tools,” and press the Install button. This will take just a few minutes, and the tools will be installed, inside the Xcode 4 application bundle.

The next problem you’ll discover is that, if you fire up a terminal window and type a command such as xcodebuild, you’ll get the Xcode 3 command line tools by default. That is not what I want. So the next step is to modify your .profile file, or whatever you normally use to control the PATH environment variable, and add these paths near the beginning:

/Applications/Xcode.app/Contents/Developer/Tools
/Applications/Xcode.app/Contents/Developer/usr/bin

Step 4: Device debugging

If you’re like me, you have a pile of devices you use for testing and debugging. Both Xcode 4 and Xcode 3 are able to install and debug apps on all my devices, which are running versions of iOS from 3.1 to 5.1.

The trick is to start on Xcode 4. Connect your device to the 30-pin connector, open Xcode 4, and look in the Organizer window. If this is the first time you’ve connected this device, it will ask you if you want to use it for debugging, and it may have to download some files to make that possible. Eventually, the little LED next to the device should turn green. After that, exit Xcode 4, open Xcode 3, and try it there. It looks like Xcode 3 copies some files from wherever Xcode 4 stashed them, and then it’s off to the races.

Aftermath

I’ve been using this setup for a number of months now. What I’ve discovered is that Xcode 3 is unfortunately pretty crippled when run on Lion. Debugging via GDB is impossible. Source code windows often have bogus titles applied. Various other cosmetic bugs abound. In short, Xcode 3 is not nearly as pleasant to use as it was on Snow Leopard. But it’s still better than Xcode 4, for the most part, in my opinion. So I soldier on.

And … fin

As of this writing, it is now a few months later, and I use Xcode 4 all the time. I still don’t like it, but there are way too many things that Xcode 3 can’t do anymore, and switching back and forth all the time is giving me a headache.

I did save the Xcode 3 versions of Pixie and Property List Editor, however. You can download a more recent version of Pixie from Apple’s developer site, but it’s not as good as the old one, and the icon is uglier. With Xcode 4, you’re expected to edit property lists within the IDE itself, but that’s often not very convenient. If you’re going to follow my lead, be aware that Property List Editor won’t work without PlistEdit.framework, which is installed in your /Developer folder along with all the other Xcode 3 stuff.

And with that, I am officially giving up the fight. You win, Apple. I sure wish Steve J. had been forced to use Xcode as much as I do. I bet it wouldn’t have turned out like this.

NSLog() sucks

July 18, 2009 8:15 am

In a previous installment I explained why printf() sucks, and how I fixed it. Today I am going to focus on NSLog(), which sucks even worse.

Why NSLog() sucks

Here’s a typical NSLog() call:

  NSLog(@"hello: %d", 6);

Note that it doesn’t require a newline character at the end of the format string. So we’ve made a little progress over printf(). It’s not until you see the output that we get to what I think is wrong with it:

  2009-07-18 08:48:29.067 nslog_sucks[44201:10b] hello: 6

Sigh. Just as with printf(), NSLog() is optimized for a corner case I hardly ever need. The assumption is that I would always want to know when this action took place down to a thousandth of a second, and that I’d want to see the name of the program doing the output, the program’s PID, and so on. The output I’m interested in is drowned out by unimportant noise.

Replacing NSLog() with something better

This is how NSLog() is defined, in NSObjCRuntime.h:

  FOUNDATION_EXPORT void NSLog(NSString *format, ...)
   __attribute__((format(__NSString__, 1, 2)));

At first glance, it appears that this would give you the same sort of warning that you get with printf() if the format string doesn’t match the arguments supplied. Sadly, I’ve never been able to coax GCC into supplying warnings in that case. But I added the same __attribute__ decoration to my NSLog() replacement, in case this is just a bug in current versions of GCC that will be fixed at some point in the future.

Finally, here’s the source code for nlog(), my NSLog() replacement that doesn’t fill the screen with unnecessary details. The header file, nslog_sucks.h:

// nslog_sucks.h -- an NSLog() alternative // by allen brunson  july 18 2009 #ifndef NSLOG_SUCKS_H #define NSLOG_SUCKS_H #include <Foundation/Foundation.h> // nlog(), a better NSLog() void nlog(NSString* nfmt, ...) __attribute__((format(__NSString__, 1, 2))); #endif  // NSLOG_SUCKS_H

And the implementation file, nslog_sucks.m:

// nslog_sucks.m -- an NSLog() alternative // by allen brunson  july 18 2009 #include <stdio.h> #include <stdlib.h> #include <Foundation/Foundation.h> #include "nslog_sucks.h" void nlog(NSString* nfmt, ...) {     va_list    args = NULL;     NSString*  nstr = nil;         va_start(args, nfmt);     nstr = [[NSString alloc] initWithFormat:nfmt arguments:args];     va_end(args);         puts([nstr UTF8String]);         [nstr release];     nstr = nil; } int main(int argc, const char** argv) {     NSAutoreleasePool*  pool = [[NSAutoreleasePool alloc] init];     nlog(@"hello from nlog: %s %d", "text", 2);         [pool release];     pool = nil;         return 0; }

printf() sucks

June 23, 2009 1:44 pm

I am a big fan of printf()-style debugging. It helps you get an overview of a problem that traditional debuggers are not so good at. So it’s a bit unexpected that I do not like printf() itself.

Why printf() sucks

printf() is optimized for a weird corner case that you almost never need. You’ll no doubt recognize this as standard usage:

  printf("Hello, World!\n")

Notice that newline character at the end. It’s a pain to type. As best as I can tell, it exists so you can do this:

printf("Starting long-running operation ..."); // long-running operation goes here printf(" finished.\n");

… which causes the output from both printf() calls to be printed on the same line. Swell. How many times have you needed to do that? I first started programming in C in the late eighties, and my lifetime total so far is zero. I typed thousands of unnecessary newline characters before I finally wised up and wrote a replacement.

Format strings are error-prone

The most likely problem you’ll have with printf() and functions like it is a mismatch between the format string and the variables presented to it. For example:

  printf("Two strings: %s %s\n", "text");

The format string calls for two strings to be printed, but you’ve only provided one. The call to printf() might work fine, crash, or print weird results, depending on what happens to be lying around on the stack. If your compiler is GCC — and it probably is, if you’re programming for any UNIX variant, including Mac OS X — there is a good workaround. Here’s my definition for echo(), my printf() replacement:

  void echo(const char* tfmt, ...) __attribute__((format(printf, 1, 2)));

That weird __attribute__ business is a GCC-ism that means “this function works like printf(), and here’s the argument numbers to use for the format string and the variable args, respectively.”

This feature doesn’t work unless you specifically enable the proper GCC warning. If you’re using makefiles or the command line, pass -Wformat to the compiler. If you’re using Xcode, bring up the project information window. In the “Build” tab, there’s a section called “GCC 4.0 – Warnings.” The warning you want is labeled “Typecheck Calls to printf/scanf,” which should be enabled. Once you do that, then when you write code like this:

  echo("bad format: %s %s", "text");

The compiler will give you this warning:

  warning: too few arguments for format

… which saves you from the undefined behavior your program was about to be subjected to.

(C++ introduced cout, which is a printf() replacement. It handily works around the format string issue discussed here. I’ve always felt that cout introduces more problems than it solves, so I personally avoid it.)

Functions you can use

The sample code that follows includes three functions you might want to use in your own programs.

echo() — works exactly the same as printf(), except it doesn’t require a newline at the end of its format string.

sfmt() — works exactly the same as echo(), except it puts the formatted contents into a std::string object, rather than printing to stdout.

fmtArg() — useful if you want to build your own printf()-like function similar to echo() or sfmt(). Have a look at how echo() uses it, which should be enough for you to get started.

Example code

First the header file, printf_sucks.h:

// printf_sucks.h -- printf() alternative // by allen brunson  june 18 2009 #ifndef PRINTF_SUCKS_H #define PRINTF_SUCKS_H // sfmt() and support functions std::string fmtArg(const char* tfmt, va_list args); std::string fmtArgLarge(int32_t byteCount, const char* tfmt, va_list args); std::string sfmt(const char* tfmt, ...) __attribute__((format(printf, 1, 2)));   // echo(), a better printf() void echo(const char* tfmt, ...) __attribute__((format(printf, 1, 2))); #endif  // PRINTF_SUCKS_H

Now the source file, printf_sucks.cpp:

// printf_sucks.cpp -- printf() alternative // by allen brunson  june 18 2009 #include <assert.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string> #include "printf_sucks.h" void echo(const char* tfmt, ...) {     va_list      args = NULL;     std::string  text;         va_start(args, tfmt);     text = fmtArg(tfmt, args);     va_end(args);         puts(text.c_str()); } std::string fmtArg(const char* tfmt, va_list args) {     static const int32_t  kBufferSize = 2 * 1024;         // the extra four bytes are to guard against buffer overruns     char     cbuf[kBufferSize + 4];     int32_t  size = 0;     assert(tfmt && tfmt[0]);     size = vsnprintf(cbuf, kBufferSize, tfmt, args);         if (size < kBufferSize)     {         return std::string(cbuf);     }     else     {         return fmtArgLarge(size, tfmt, args);     } } // called when fmtArg() didn't have a big enough buffer std::string fmtArgLarge(int32_t byteCount, const char* tfmt, va_list args) {     char*        cbuf = NULL;     int32_t      clen = byteCount + 10;     int32_t      size = 0;     std::string  text;         cbuf = static_cast<char*>(malloc(clen + 4));     if (!cbuf) return "";         size = vsnprintf(cbuf, clen, tfmt, args);     assert(size < clen);         text.assign(cbuf);         free(cbuf);     cbuf = NULL;         return text; } int main(int argc, const char** argv) {     echo("hello from echo: %s %d", "text", 2);     return 0; } // works like echo(), but puts the formatted contents into a std::string std::string sfmt(const char* tfmt, ...) {     va_list      args = NULL;     std::string  text;     assert(tfmt && tfmt[0]);     va_start(args, tfmt);     text = fmtArg(tfmt, args);     va_end(args);         return text; }

cocoa: app memory usage

May 3, 2009 6:30 pm

My least favorite part of Cocoa programming is its reference-counted memory management scheme. If you can exclusively target Mac OS X 10.5 or later, then you can use garbage collection instead, which is better. But it doesn’t work on Mac OS X 10.4 or earlier or the iPhone, so garbage collection might as well not exist, as far as I’m concerned. Yes, I know Cocoa’s reference-counting scheme has “only a few simple rules” you have to follow … yet Apple’s own apps tend to leak pretty badly. Back when I was using Mac OS X 10.4, I could only run Safari for a few hours before I had to restart it. Seems to be less of a problem in Mac OS X 10.5, but they’re likely using garbage collection these days.

So, early versions of your Cocoa programs are probably going to leak. There are ways to combat this. The primary ones are the leaks command-line tool and the Instruments app that comes bundled with Xcode, neither of which I like very much. I’d prefer that the app itself report its bad behavior. To that end, I’d like my apps to be able to tell how much memory they are using.

Surprisingly, an app’s memory usage is subject to interpretation. Suppose your app and another are both using one in-memory copy of a shared framework. Should your app’s memory total include the size of the framework or not? What if your app has a lot of memory allocated that currently lives on disk in a swap file — should you count that?

I’ve spent some time in the past studying this issue, and I’ve decided to go with a figure called the “resident set size.” This is more-or-less how much memory your app is using. Not perfect, but plenty close enough for my needs. Here’s how you can get it.

#include <mach/mach_init.h> #include <mach/task.h> #include <sys/time.h> #include <sys/resource.h> #include <stdint.h> #include <string.h> #include <unistd.h> int64_t MemoryUsage() {     task_basic_info         info;     kern_return_t           rval = 0;     mach_port_t             task = mach_task_self();     mach_msg_type_number_t  tcnt = TASK_BASIC_INFO_COUNT;     task_info_t             tptr = (task_info_t) &info;         memset(&info, 0, sizeof(info));         rval = task_info(task, TASK_BASIC_INFO, tptr, &tcnt);     if (!(rval == KERN_SUCCESS)) return 0;         return info.resident_size; }

This was difficult to write. It makes use of Darwin kernel APIs, which Google knows almost nothing about.

This works on any version of Mac OS X back to about 10.2, I think. It also works on the iPhone simulator, as well as on actual iPhone hardware. I’ve tried it myself on all these, including my own phone. The fact that this function works unmodified on both Macs and live iPhone hardware is proof positive that the two platforms use very similar kernels.

If you want to use this to detect leaks, you have to track your apps’ memory usage over time. Take a snapshot of your app’s size near the beginning of a run, then put your app through its paces for half an hour or so. Is the app’s memory usage trending up?

In addition to being useful for tracking leaks, I simply appreciate knowing how much memory my apps are using. There’s a definite upper limit on how much RAM you can allocate on an iPhone, and there’s no virtual memory at all. If your iPhone app exhausts all physical memory, it can’t start swapping to disk, it’ll just get killed.

I’ve noticed that the app I’m working on now uses 14MB in the simulator, but only 8MB on real iPhone hardware. Probably because simulator apps are really just modified Mac apps. Windows, views, and other user interface elements on the Mac are no doubt heavier than their iPhone counterparts.

iphone newbie: view coords, UITextField

March 3, 2009 7:49 am

View coordinates for iPhone

I count three people in my access logs who got here by searching for iPhone programming material, two who are trying to create nibless apps. Rock on, fellow Interface Builder haterz!

iPhone programming is typically very similar to Mac programming. One big change I’ve noticed is that they’ve moved the origin for view coordinates. For NSView on the Mac, the origin point is at the lower left corner, Y coords get bigger as you move up the window. That always seemed deeply, profoundly wrong to me. I guess I’m not the only one who feels that way, because on the iPhone, the origin point is now in the upper left corner, with Y coords getting bigger as you move down the view.

To make matters worse on the Mac, it’s possible to have an NSView with “flipped” coords. In that mode, the origin point is at the top left, as god intended. Some of the stock views are like this, I think NSTableView is one of them. Those views will go crazy if you try to set them back to the “normal” Mac way, displaying their contents incorrectly. What a mess. Looks like iPhone/UIView doesn’t have the “flipped” concept, so everything’s cool again.

View coordinates for Mac

Well, except for other annoyances. Today’s culprit: UITextField. This is the standard one-line text input control for the user to type into, analogous to the Mac’s NSTextField. Way, WAY more complicated than it should be. Every single thing that happens to it in its lifetime, you have to write custom code for.

Creating a UITextField and adding it to a parent view is a trial-and-error affair, sprinkled with magic pixel counts like 30.0 and 4.0 and so on. It’s not just me, that’s the way they do things in Apple’s UICatalog sample app, which shows you how to create most control types. This is bad. What if the dimensions of the control change in the next iPhone software update?

When the user touches the control, the onscreen keyboard pops up. Surprise! It will almost certainly cover the UITextField the user is typing into, so they can’t see what they’re doing. The next step is that you have to write code to scroll your view up to get out of the keyboard’s way when it appears, then scroll the view back down when the keyboard disappears. Why isn’t the iPhone OS doing this for me? Madness!

Now you must add code to your view controller’s viewWillAppear: method, to catch notifications for when the keyboard appears and disappears. Then add more code to viewWillDisappear: to disable those notifications. Then write a method that gets called when the keyboard appears or disappears, to scroll your view up or down by a magic number of pixels. UICatalog hard-codes the value 150.0, which is I suppose the height of the onscreen keyboard. That wasn’t quite right for me, I discovered I needed it to be 166.0. I’m sure that will be the right value to use always and forevermore, right Apple? Sheesh.

Finally, the keyboard won’t ever go away unless you write more code to dismiss it. You must make your view controller the text control’s delegate and write a textFieldShouldReturn: method so you can do something with the Enter key and tell the keyboard to go away. Six new methods later, your quest is at an end. Until the next time you need a UITextField.

nibless

February 23, 2009 7:59 pm

Update: The linked blog post in this article that explains how to create a nibless Xcode project is now dead. Go read this post instead.

This might sound heretical, but here goes: I don’t like Interface Builder.

I used the 2.x versions to build this. I got along with it acceptably well at the time, I guess, although it was never my favorite program. Then Apple completely rewrote it from the ground up for 3.0, whenceforth it didst suck, yea verily.

My complaint is a simple one: Interface Builder is 87 billion times more complex than it should be. Dozens of windows, hundreds of tabs, thousands of buttons, sliders, text input fields, check boxes, outlets, hinges, beads, knobs, joints, pipes, and zippers. Every time I start it up, I dread the ordeal I know I’m in for. It takes me half an hour to find the one check box I need in a sea of extraneous crud. Once I get a view or window set up appropriately, the steps I went through to get there are not easily documented or remembered.

I know that laying out user interfaces and wiring up controls is a big job. I know that somebody must need all that crud I never use, or it wouldn’t be there. But couldn’t Apple use its legendary user interface skills to de-emphasize the infrequently-used parts? I’m dyin’ here.

If you’re writing a Mac/Cocoa app, I guess you’re stuck with it. You’ve probably got at least a few fairly complicated windows to manage, along with dozens of menu items. But if you’re writing an iPhone/UIKit app, the value proposition changes. iPhone apps tend to have only a handful of user interface objects and connections. In this scenario, Interface Builder’s weaknesses outweigh its strengths.

It’s easy to assume that it’s impossible to build an iPhone or Mac app without Interface Builder. As a matter of fact, I once spent several months figuring out how to build Cocoa apps without NIBs, because I was writing a cross-platform GUI framework, so obviously they had to go. It wasn’t easy, because it’s not done very often, but I succeeded. And the first version of the iPhone SDK didn’t even give you the opportunity to use Interface Builder, you were forced to create your user interface in code.

Now we reach the part of the blog entry where I should tell you how to make an iPhone app without NIBs. Alas, this gentleman has already done a far better job of it than I would have. So you can instead read what he wrote, secure in the knowledge that someone else produced a solution, while I produced a bunch of hot air and whining. You’re welcome.

I’m now working on the user interface for my first iPhone app. I have several views set up, all completely NIB-free. It’s far preferable to create a user interface element in 10 lines of code, rather than making yet another soul-destroying 20-minute slog through Interface Builder. I suppose it’s possible that I’ll run into some situation that forces me to reconsider, but at this point, I’m willing to go far, FAR out of my way to avoid having to invite that sad piece of software back into my life, thank you very much.