Archive for the ‘Coding’ Category

Building the Latest CPTestApp in the CorePlot Project

Friday, February 20th, 2009

CorePlot.jpg

Well... I'm stumped. I had been working on a few things for the unit testing framework yesterday, and today I wanted to look at this problem that had been reported on the Google Code site. Basically, there's a build problem, and I wanted to track it down.

First thing: build the code and reproduce the issue. It builds fine - I can't see the error, but when I run it within Xcode, I get the following on the Console:

    [Session started at 2009-02-20 12:05:37 -0600.]
    dyld: Library not loaded: @loader_path/../Frameworks/CorePlot.framework/Versions/
        A/CorePlot
    Referenced from: /Users/drbob/Developer/core-plot/examples/CPTestApp/build/Debug/
        CPTestApp.app/Contents/MacOS/CPTestApp
    Reason: image not found

  The Debugger has exited due to signal 5 (SIGTRAP).The Debugger has exited due to
      signal 5 (SIGTRAP).

OK, this should be easy - it's got to be that the CorePlot.framework isn't properly in the project and that's what's missing. So I looked into that. But it's there. Just where it should be. Then I dug into the built CPTestApp.app wrapper and right where it's supposed to be is the framework! I'm stumped.

I looked at the project settings... nothing popped out at me. I cleared the Xcode project file and reloaded it from the repo... no difference. I even did what I thought should have been done and added in the CorePlot.framework to the Linked Frameworks 'folder' in the project, and still nothing.

I'm blown away! So I finally shot an email to the mailing list and we'll see if we can't find out what's up. I'm really stumped. It used to work!

UPDATE: HA! I got it figured out. First, the path for the library is encoded into the Framework - not in the app using the framework. OK, now that I knew that, I started looking at the CorePlot Framework build parameters. I noticed the one that I was looking for in the Deployment section:

Target 201CCorePlot201D Info

Originally, the Installation Directory was set to:

  @loader_path/../Frameworks

and that was what was being set in the dynamic library, and compiled into the app's executable. What I needed to change was the path to:

  @loader_path/../Resources/Frameworks

and then it was able to find the framework and run.

OK, this wasn't obvious in the least. I Googled this guy and came up with nothing other than the fact that the name was in the shared library - which I had remembered as soon as I was reading the post. So, at least now, I can see the error, and hopefully get a handle on it.

UPDATE: Drew commented that he had changed the @loader_path to @executable_path a while back, but that there may have been issues in the merge that was done to get the testing code working. So I emailed back that he's free to change it back and I'll just pick up the right version in the next 'svn update'. Sounds good to me. Glad to see I wasn't totally missing it.

[2/21] UPDATE: Barry pointed out that @loader_path is the right value - but the project was not configured to copy the framework into the right location. So he fixed that. It builds fine now.

Did a Little Work on CorePlot Test Cases

Thursday, February 19th, 2009

CorePlot.jpg

I'm trying to see how an Open Source plotting package for Cocoa on Mac OS X goes. It started a few weeks ago, and I think it's the right thing to do as it's the kind of thing I've wanted to have for the Mac for ages, and being a part of it almost guarantees that I'll understand it well enough to make use of it. So I'm trying my hand at this kind of thing.

Today I looked at the new testing framework someone put in. I can see the value of automated testing but I also see the problems. Today it was sloppy includes, poor test writing and missing test data. They were fixed easily enough, but it brings to mind the problems I see in automated testing in the first place: What do you really test?

I'm all for testing the public APIs of classes. That's what the class is supposed to do, and how it's supposed to do it. But private methods are another thing. I think that's asking for a ton of grief. If the method is useful enough, and important enough to test, then maybe it should be in the public API. If it's not that important, then testing the public API should exercise the private implementation details.

The guy that threw this test frame together didn't share my ideas. He's got compiler warnings testing private methods, and I just think that's not right - from several points of view. First, the testing, and then the compiler warnings. There just shouldn't be any. Period. It's so easy to remove these, and they are there for a reason - you're making a mistake. Maybe not a big one, but it's a mistake, and you need to stop right now and fix it.

Given that this is open source, it's not going to get fixed unless I fix it, but that's OK too. I don't mind being in that role for this project. It's interesting and the outcome is something I've wanted for a long time. We'll just have to roll with the punches and see where it goes.

Interesting Application of Thread-Safe Lockless Data Structures

Tuesday, February 17th, 2009

cplusplus.jpg

I was looking at lockless data structures for multi-threaded programming again this morning, and I came across a link to TransactionKit. This sounds very interesting to me. Basically, the group has implemented a thread-safe NSDictionary and NSMutableDictionary pair that are completely safe for multi-threaded environments, use no locks, and offer the basics of transactional integrity: begin transaction, commit and rollback functionality. And I have to admit I'm very intrigued.

The biggest challenge to me in working with these lockless data structures is that you might not know you're going to need them when you start the project. It's only after you build the project, see it scale for a while, and then hit a fundamental limit that you see it's time to switch over. Problem is, by then, you're stuck. You've got all this code that uses one form of thread-safety, and now what you realize you need is something else all together. But you can't justify the complete re-write.

What you need is lockless alternatives to standard data components that are easily swapped in when the 'going gets tough'. For example, I like TransactionKit's take on the inclusion in Objective-C - make it look like a simple NSDictionary and NSMutableDictionary so that it's a simple search and replace for the vast majority of the retrofitting. This makes things a lot simpler.

But now I'm looking at the CKit stuff. It'd be one thing to have a truly lockless CKFIFOQueue. Then another that uses mutexes for those times when it's not a major issue for speed. Finally, one that uses the lockless atomic calls to make it appear to be lockless, in fact, you can even simply No-Op the lock() and unlock() methods in the subclass, but all the while, the thread-safe behavior is in play.

The problems with general coding are a lot more difficult, however. Take for example, the retain/release code I posted a few days ago. That's not so simple. Previously, I had:

void Instrument::retain()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // now up the count
    ++mRetainReleaseCount;
    // see if it's in the pool to be released, if so, remove it
    if (mRetainReleaseCount == 1) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        mReleasePool.remove(this);
    }
}
 
void Instrument::release()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // no decrease the count
    --mRetainReleaseCount;
    // see if it's an error
    if (mRetainReleaseCount < 0) {
        getLog() << l_error.setErrorId("Instrument.release")
                 << "the release count for " << mmSym() << " went negative! ("
                 << mRetainReleaseCount << ") This is a serious problem." << endl;
    }
    // see if it's at zero, and then if so, add it to the pool
    if (mRetainReleaseCount <= 0) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        if (!mReleasePool.contains(this)) {
            // log that we're going to dump it in the trash
            getLog() << l_error.setErrorId("Instrument.release")
                     << "adding " << mmSym() << " with retain cnt="
                     << mRetainReleaseCount << " to garbage" << endl;
            // ...and then do it.
            mReleasePool.addBack(this);
        }
    }
}

where the critical points were one (1) in the retain() code and anything less than or equal to zero in the release() code. This was due to the logical assumption that the value of mRetainReleaseCount would be initialized to 1. But what if we have it initialized to zero? Then the critical points are zero for the retain() code and anything negative for the release() code.

#include <asm/atomic.h>
 
void Instrument::retain()
{
    /*
     * Increment the count. If it's zero, then we were ready to flush this guy
     * and now we need to pull him out of the garbage before he gets flushed.
     */
    if (atomic_inc_and_test(&mRetainReleaseCount)) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        mReleasePool.remove(this);
    }
}
 
void Instrument::release()
{
    /*
     * Decrement the count, and if we are negative then it's time to add this
     * guy to the release pool for deletion.
     */
    if (atomic_add_negative(-1, &mRetainReleaseCount)) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        if (!mReleasePool.contains(this)) {
            // log that we're going to dump it in the trash
            getLog() << l_error.setErrorId("Instrument.release")
                     << "adding " << mmSym() << " with retain cnt="
                     << mRetainReleaseCount << " to garbage" << endl;
            // ...and then do it.
            mReleasePool.addBack(this);
        }
    }
}

if I then initialize the value of mRetainReleaseCount with:

    ...
    mRetainReleaseCount(ATOMIC_INIT(0)),
    ...

in the constructor's code, then we'll start with zero, climb positive, and then when we go negative we'll by tossed into the release pool for the next cycle on the garbage collector thread. Since the garbage collector thread also checks the retain/release count before it wipes out the instance, we're safe.

At least I'm pretty sure we are...

Well... here's the problem I see now. Because we have removed the mutex on the retain() and release() methods, we can be doing both at once. The count will be handled properly, but what if the release() hits it's counter operation first, but the retain() method's if() body executes first to get the lock on the second mutex?

Now we're in trouble. The counter will be saying 'leave the instrument out of the pool', but the code will execute in the order indicating that the instance will be placed into the pool. Crud.

Yup, this is not easy. I was ready to put the code into play, but there's no guarantee that the body of the conditional will execute in the same order as the atomic operation. This means that it's possible to have them in the wrong order. This, in turn, tells me that the greatest application of these atomic operations are in the thread-safe lockless data structures. That's about it. When you have two operations that need to be treated atomically, then you're sunk. Darn.

Looking at Atomic Operations for Lockless State Management

Friday, February 13th, 2009

cplusplus.jpg

I was listening to an interesting podcast today about lockless state management with atomic operations and got to thinking that there's a lot this can be used with if you spend a lot of time to get things into simple word-sized blocks. But there's a ton that can be done just as-is.

What I'm thinking about right now is the simple retain/release counters that I have on my instrument objects in the fast-tick server. Face it... they are about as simplistic as you can get. This article by IBM talks about the atomic operations in linux, and looking at a few include files, I can see that it's supported in the version we're using simply by including asm/atomic.h. Good news.

What I'll need to do is read up more on this and see if I can fit these easily into the retain/release code. If I can, then it's probably worth trying. The number of times I hit that code is non-trivial, and that's all kernel-space work. Better to be in user-space and not have the overhead. The code I have now looks a lot like this:

void Instrument::retain()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // no up the count
    ++mRetainReleaseCount;
    // see if it's in the pool to be released, if so, remove it
    if (mRetainReleaseCount == 1) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        mReleasePool.remove(this);
    }
}
 
void Instrument::release()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // no decrease the count
    --mRetainReleaseCount;
    // see if it's an error
    if (mRetainReleaseCount < 0) {
        getLog() << l_error.setErrorId("Instrument.release")
                 << "the release count for " << mmSym() << " went negative! ("
                 << mRetainReleaseCount << ") This is a serious problem." << endl;
    }
    // see if it's at zero, and then if so, add it to the pool
    if (mRetainReleaseCount <= 0) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        if (!mReleasePool.contains(this)) {
            // log that we're going to dump it in the trash
            getLog() << l_error.setErrorId("Instrument.release")
                     << "adding " << mmSym() << " with retain cnt="
                     << mRetainReleaseCount << " to garbage" << endl;
            // ...and then do it.
            mReleasePool.addBack(this);
        }
    }
}

The trick will be to do the entire method atomically. I can't just change the count. The checks are also critical, but maybe if I do the change, and keep the flag, that will work. Problem might be that another operation gets in the and wants to undo my work, but I come later... it's not an easy problem to solve with a single atomic operation on an int.

Certainly something to think about.

Cleaning Up the PrettyPrint in Python’s xml.dom.minidom

Thursday, February 12th, 2009

python.jpg

OK... well, this has been an interesting exercise. I've been working on a Python script to grab data out of a system here, and generate an XML file for a vendor upload. It's a big file, and there's a lot of things that have to go into it, but I wanted to be able to do as much as possible from within the Python code itself. If I had to post-process it and add tags later, then that's OK, but I didn't want to start with that plan. I wanted to make the utmost of python's capabilities for this task.

For the most part, I haven't been disappointed. Python has a pretty nice XML DOM system (xml.dom.minidom) built-in, and I was able to create the document very easily. The problem came in dumping it to a file. There were two basic ways I could dump it:

<exchangeTraded><id type="SEDOL">B10RB15</id>
<positionName>1605=JP</positionName><amount>-214.0</amount></exchangeTraded>

where it all appeared on one 'line' and no spaces were to be found, for the 'simple' XML output, and:

<exchangeTraded>
    <id type="SEDOL">
        B10RB15
    </id>
    <name>
        1605=JP
    </name>
    <amount>
        -214.0
    </amount>
</exchangeTraded>

for the 'Pretty Print' output. Neither was really good, but as the lesser of two evils, the second one was far more readable for the size of the file I'd be sending. But I knew that I needed to get back to this as soon as reasonably possible and fix this up with a decent output processor.

Today has been that day. I was quite lucky that I got a good head-start with Google, and was able to put together the following replacement for writexml():

def new_writexml(self, writer, indent="", addindent="", newl=""):
    # indent = current indentation
    # addindent = indentation to add to higher levels
    # newl = newline string
    writer.write(indent + "<" + self.tagName)
 
    attrs = self._get_attributes()
    a_names = attrs.keys()
    a_names.sort()
    # lay down the attributes on the tag
    for a_name in a_names:
        writer.write(" %s=\"" % a_name)
        xml.dom.minidom._write_data(writer, attrs[a_name].value)
        writer.write("\"")
    # now lay down the child nodes
    if self.childNodes:
        if len(self.childNodes) == 1 and \
                self.childNodes[0].nodeType == xml.dom.minidom.Node.TEXT_NODE:
            writer.write(">%s</%s>%s" % (self.childNodes[0].data, self.tagName, \
                        newl))
            return
        writer.write(">%s" % (newl))
        for node in self.childNodes:
            node.writexml(writer, indent + addindent, addindent, newl)
        writer.write("%s</%s>%s" % (indent, self.tagName, newl))
    else:
        writer.write("/>%s" % (newl))

where the arguments are exactly the same as the original version, we've just cleaned up the printing of the child nodes when there's only one and that one is a text field. To install it into the proper place in the runtime, I simply need to:

#
# This is the main working section of the script
#
def main(argv):
    # hook in our new XML DOM writing code
    old_writexml = xml.dom.minidom.Element.writexml
    xml.dom.minidom.Element.writexml = new_writexml

and it's good to go with the same old code.

The results are perfect:

<exchangeTraded>
    <id type="SEDOL">B10RB15</id>
    <name>1605=JP</name>
    <amount>-214.0</amount>
</exchangeTraded>

I'm sure I'll be using this again very soon, and I wanted to document it so I didn't forget it. Really quite simple, but the effects are quite dramatic on a large file with thousands of nodes.

Pleasantly Surprised with Python Today

Wednesday, February 11th, 2009

python.jpg

I've been writing an XML file generator in Python hooking into a few data sources (systems) here at the Shop. I'm really quite pleasantly surprised at how easy it is to do all the little things you need to do. Formatting, logging, database, it's all there. With a decent access to the data, and a nice object model, it's downright pleasant.

I have to admit I'm surprised. I expected a more 'stripped down' language than this has shown itself to be. Yes, it's supposed to be all wonderful and that, but until you really need to dig into it, refactor it, and do all the little things that you're not going to find in a simple 'Hello, World!' app, you can have your doubts, as I did mine.

The object model is nice, if not a little confusing. The proliferation of self is a trifle annoying - can't this be inferred from scope? Maybe not. It's something that I can get over, but it is a bit odd at first.

The indenting at least makes things look nice. The speed is first-rate, I'll give you that. There isn't anything I can complain about there.

If I spent a lot of time in it for a few weeks, I'm sure I'd pick up a lot of habits that would make it very nice to write in. Libraries, or finding those libraries like the XML DOM, are real time savers, and yet it takes time to look them up, learn how to use them, etc. Time worth spending, but time you need to spend.

I have to say... it's not PHP, but it's really quite nice.

Disappointment in Subversion’s Schema Changes

Wednesday, February 11th, 2009

svn.gif

I was working with a subversion workarea (the check-out of the repository) today and tried to do a simple 'svn status' and got the following on the console:

  svn: This client is too old to work with the working copy '.';
      please get a newer Subversion client

What?! I had been using subversion version 1.3.2 (FedoraCore 5) for a while, I've used 1.4.4 (Mac OS X 10.5.6), even 1.4.3 on a shared install for Linux at the Shop - but I've never seen this.

So I do some digging. First, upgrading the FedoraCore 5 subversion install to 1.4.x is virtually out of the question. There are so many links to that RPM that it's possible to build from source and put it in /usr/local/bin/, but it's just as easy to soft-link the shared drive version (1.4.3) into /usr/local/bin/ and leave it at that.

So why the horrible upgrade path? Sure, subversion uses the apache libraries and such to provide functionality so that they didn't need to write it. That makes sense - to a point. But if I have links to 50 different shared libraries and I want to update my source control client - I shouldn't have to upgrade my OS. It should be something relatively simple. But it's not.

OK, RedHat (Fedora) can take a bit of the blame and the package management. But not all. There's not reason for this. CVS doesn't need it. Git doesn't need it. There's nothing that requires it. It's just the way they decided to do it. Freeze subversion at the OS level (by RedHat), and build it on so many shared libraries (subversion). Together, they make it ridiculous to upgrade the subversion client on a Fedora Core box.

But the big issue was not that the update was exceptionally hard, it was that is was required at all! What were they thinking? Honestly. What version control system makes a repository or workarea schema change that locks out an older version of the client? Amazing. I understand that they are trying to bring better features to the system. That's great. But they have a schema that's been established for a long time. They decide to change it now? I'm blown away.

Don't get me wrong. I understand progress. I understand new features. Xcode updates the old files and makes them unreadable by the previous version. Got it. But Xcode is not a source control system. The problem domain didn't change on them. If that didn't change, they they either did a very poor job putting the schema together in the first place, or they believe source control needs to have new bells and whistles for some reason.

In either case, I am re-affirming my stance with subversion. Won't use it except where I'm forced to. And then, only if there's no possible better alternative. CVS still wins, in my book, for centralized SCM, and Git wins for decentralized SCM. This isn't something that needs to have fancy new features. You need to have stability and reliability. Period.

Want to change the schema? Fine, make it part of the schema - XML does it. Then the client doesn't have to change as it reads all the descriptive information about the repo at runtime. Again, the client doesn't need to change.

I am forced to believe they are either poor designers or interested in shiny buttons. Neither of which is never a good thing. More than anything else I'm stunned that they'd mistakenly design the schema. This was an update of CVS, they knew all the 'limitations' of CVS, and set out to 'fix' them. That they missed the primary reason for source control -- stability, is beyond me. It's just amazing.

I'll keep my distance from subversion, thanks. There are plenty of other, better, alternatives out there.

Why Oh Why Do Some Coders Try to Get Tricky?

Tuesday, February 10th, 2009

python.jpg

I've run into this a lot in at least a few languages - Java and Python. The coder thinks he's saving something by saying:

  import java.util.Date;
  import java.util.Vector;
  import java.util.Stack;

as opposed to simply saying:

  import java.util.*;

I mean really... what are we saving here? Nothing. Exactly nothing. The reading of a file? No... it's still got to read what it reads for the three classes from the one jar file. Microseconds on the compile - maybe. But what have you done? You've forced all additional developers to enumerate all classes they are using. Why? Is it really that important?

It gets worse in Python. I ran into the following code:

  import logging.config, os, sys

where the normal developer would say:

  import logging, os, sys

Can't imagine we've gained anything by just loading the config if we're really do any logging, chances are we're going to actually log. But what I found out today is that this can cause a ton of trouble in systems with the thread package built-in and using the dummy_thread.py stub.

For these guys, you really need to do the following:

  try:
      import thread
  except ImportError:
      import dummy_thread as thread

and in doing this we are able to use the thread package as if it always existed - even when it doesn't. Decent. And the logging package does this - so long as you import it properly. If you try to, oh, I don't know... say import just the logging.config package this isn't done and then all of a sudden the dummy_thread.py isn't pulled into play and you get import errors in the python logging libraries.

Argh!

So I have to ask around and see who might have done this and for what reason. I don't want to make a change that will break something just to get something else to work. We need to have everything working, and if that means we need to put more work into this guy, then so be it, but I'm very clear that this is code written here and not a part of the core Python code.

It's something I'm going to have to deal with on this little project. It's not fun, but it's what I have to do.

Documentation – Why Joe Coder Can’t Write

Tuesday, February 10th, 2009

cubeLifeView.gif

I'm continually amazed at the lack of documentation that most developers I meet write. They don't think it's necessary for their work - after all, they wrote it. Who else needs to understand it? Who else needs to use it? Well... if they need to use it, they'll come and talk to me and I'll walk them through it and then they'll be OK.

It's an incredible double-standard. If they ask for docs from me for something (and most developers I work with have, from time to time) I give it to them. Why? Because I wrote it. I wrote it for myself, and then built the code based on those docs. I know they didn't write the docs otherwise, they'd give them to me.

No, and I've run into a class of developer that if I don't have docs for a process or procedure ready, they want them as opposed to the "talk through". I have to provide it for them so they can make their process or procedure. But when I ask for it, they think I'm being unreasonable. These people are just lazy, no two ways about it.

But the general mass of developers that don't write docs, or even comment their code so that it's at least able to be followed by someone are the ones that get me. They know the value of the docs, but still they refuse to write them. They know it'd make things a lot easier, but they aren't concerned about making the other guy's life easier... they had it hard, so why make it easier on the guy following them? Selfish, is all I can think of. Unkind as well.

So I'm sitting here realizing that I have very little in common with developers like this. I'll continue to work with them, but it's a waste of my time to expect them to change. Maybe they'll run into someone that gets them to write them, and then see the value in having them. But until that day comes there's nothing I can do to make them see the err of their ways. Sad.

Fun with AutoRelease Pools in Cocoa Programming

Thursday, February 5th, 2009

xcode.jpg

I was talking to a friend today about the use of [[obj alloc] init] and the AutoRelease pools. Turns out, Apple recommends not to use them in iPhone applications. And that got us to dissecting them, to figure out why Apple wouldn't want this very handy feature used in iPhone apps.

First, we need to lay a few ground rules. When I have the code:

  MyObject*  obj = [[MyObject alloc] init];

the reference count on obj is set to 1. What really does this? Well, it's the alloc. Create it (alloc), and it's reference count is 1. Simple rule to remember.

So what if I want to create something, use it in my method, and then get rid of it? In these cases, you know the lifetime of the object is within the scope of your method, and in that case, you can choose to use the more efficient:

  MyObject*  obj = [[MyObject alloc] init];
 
  // ...use this guy for anything you need
 
  [obj release];

the last line in the code sample balances the alloc in the first line and reduces the reference count by one, and when zero, the object is removed. Easy. But this is very 'manual' - a lot like the C malloc() and free(). But it is efficient. So you just have to decide what's more important - efficiency or a little leeway on the object lifecycle?

For example, say we might want to keep this, but we might not. Then what? If we had written the code like this:

  MyObject*  obj = [[MyObject alloc] init];
 
  // ...use this guy for anything you need
 
  // if we have no error, keep this guy
  if (!error) {
      [self setObject:obj];
  } else {
      [obj release];
  }

Now the question becomes Can't we make this cleaner? and the answer is you bet we can:

  MyObject*  obj = [[MyObject alloc] init] autorelease];
 
  // ...use this guy for anything you need
 
  // if we have no error, keep this guy
  if (!error) {
      [self setObject:obj];
  }

with the addition of the autorelease call, we have placed this instance into an NSAutoreleasePool and at the end of the next run loop, it will clear out the pool, calling release on each item in the pool, and those whose retain counts hit zero are going to be freed.

Why is this better? Well... because when we create it, we can put it in the state that says "Hey, if I don't do anything with this guy, clean him up, but leave me the option to keep him." This, of course, is not as efficient as the first case, but this is far more flexible. If there are times when you might need to keep ahold of something you've created, this is the cleaner solution.

There's also the question of the Factory Pattern. If I'm making things for (possible) consumption, then I need to autorelease them before I return them. This allows the caller to either retain them or not, and if not, then at the end of the next run loop, the NSAutoreleasePool will clear it out and be done with it.

Remember, calling autorelease doesn't change the retain count - it just puts it in a pool that eventually will release the object and then possibly free it. So, it's in the definition of eventually that the inefficiency comes it.

In general, it's a decent idea to do [[[obj alloc] init] autorelease] if you're making a few dozen things at any one time. The NSAutoreleasePool doesn't get too bug, and it's cleaned up easily enough. Also, it gives you the option of having the same initializer code for those things that might stick around, and for those that won't. But make no mistake, it's not as efficient as not using it and careful scoping of the instance lifetime.

This seems to be the point with Apple on the iPhone. It's not as efficient, and with all the things on that little guy, resources have got to be at a premium. So, if you can control the scope of your instances, then do the simpler [[obj alloc] init] with a release when you're done. But if you can't do that, then use autorelease. Just realize the impact to your application.

As a final note, here are some interesting examples of where autorelease helps. Imagine that we have the following code where we create one object, hold on to it, create another, and then message the first. This would be recognized by a C coder as the classic dangling pointer:

  MyObject*  obj = [[MyObject alloc] init];
 
  // ...use this guy for anything you need
 
  // hold on to him for a sec
  MyObject*  holder = first;
 
  [obj release];
 
  // make another - maybe with different parameters
  obj = [[MyObject alloc] init];
 
  // ...use this guy for anything you need
 
  // message the first - and it'll blow up
  [holder doSomething];
 
  [obj release];

this guy is going to blow up because the original instance is long gone, but the pointer is still being held in holder. This seems obvious, but there are tons of ways you can get yourself into this bind by managing the release yourself. You have to be very careful if you're not using autorelease.

But in the iPhone, you have to try.

[2/6] UPDATE: I knew there was a good reference on this topic. This is from an old Stepwise.com posting in 2005, but it's as true to day as then. It's got great coverage of all the rules. Certainly something to keep handy when you get a little confused about the topic.