Chris Ryland wrote:
> Uh-oh--can you explain to the uninitiates why these two code sequences
> aren't identical?
(Cleaning up the code sequences a little bit)
delegate = AppDelegate.alloc().init()
This is pretty messy, but IMO that's not PyObjC's fault. PyObjC makes
sure that Python's refcounting is synchronized with ObjC's, meaning that
if you do
x = SomeObject.alloc().init()
there is exactly one reference to the created instance: the variable
'x'. If 'x' goes out of scope, the value it's pointing to goes away.
Code snippet #1 creates an object, passes that to setDelegate_(). The
app object stores a pointer to the new instances. Normally storing a
pointer means the reference count is incremented (the object is
"retained" in ObjC terms). In pure Python, it is guaranteed this will
happen. Cocoa on the other hand has quite a few places where it uses
what I call a poor man's weak reference scheme, meaning it will store a
pointer *without* incrementing the reference count. This is to avoid
references cycles (in any straight refcounting scheme, cycles cause
leaks unless the cycles are explicitly broken). So what happens in
snippet #1 is that the app object stores a pointer, but the instance
will be freed by Python when setDelegate_() returns; after all, there
are no hard references to it anymore! So we have a stale pointer,
causing a crash.
Snippet #2 works around this by sticking the object in a (local)
variable, ensuring the object stays around as long as the variable is in
scope. Since the event loop is run in the same function, this is long
Using a variable is just one way to work around the problem, the other
one is to simply call .retain() on the delegate object, "artificially"
increasing the reference count, creating a leak on purpose. That's ok,
since the app delegate is supposed to be alive for the lifetime of the
The real solution however, is to use Interface Builder.
It should be quite rare you have to worry about this: most of the time
when Cocoa uses these "weak references", it is guaranteed the references
object is alive long enough. For example _usually_ you'll instantiate
your app delegate in your main nib file and assign it as the delegate of
the app there (by means of an outlet connection). A weak reference is
still used (as is actually the case with outlets in general!), but you
don't have to be aware of it since Cocoa will automatically do the right
thing. It's only when you manyally work with delegates (or rather,
outlets in general) you sometimes come across this problem.