|Monday, October 14, 2002|
Oops. CodeFab's connectivity blew up this morning. As such, friday.com is down. Hence, no one can download the PyObjC builds. Figures that would happen at the same time SlashDot mentions PyObjC (which had nothing to do with the outage).
I mirrored everything to the PyObjC sourceforge site. It'll do until I figure out how to do releases via sourceforge.
I was bummed to discover that sourceforge does not advertise an appropriate mime type for disk images.
A very nice email in my mailbox this morning:
I just installed your Python/Obj-C bridge and was able to take an existing Python back end and add a beautiful Cocoa UI within an hour of use. The ease of development of Python and Cocoa together at last!
Thank you, thank you, thank you!
Jonathan LaCour 5th Year Senior, Computer Science at Georgia Tech Currently Seeking Employment
Nicholas Riley released Pester today. A simple/cool little app to pester you at some point in time in the future.
Nicholas also said:
I can safely add NSTimer to the list of classes with bad documentation: the ownership model is essentially undocumented, and I spent several hours tracking down a crasher that turned out to be timer-related. Timers retain themselves while they're active, but something else (the runloop?) retains them as well. When you invalidate a timer or it expires, the retain count is 1, but if you try to release it, a bit later your program goes kaboom. The timer is autoreleased, so the best way to establish ownership is to retain it when you create and schedule it (retain count: 3), then perform an invalidate (has no effect if timer is already invalid) and release when you're done, relying on the later autorelease to perform a dealloc.
Actually, the NSTimer behavior is exactly in line with the rest of NSFoundation.
Namely, if you call any of the four factory methods, all four return an autoreleased instance of NSTimer as they should. That the NSRunLoop also retains a scheduled timer is irrelevant (though, in Nicholas's case, it caused the retain/release bug he had to be harder to track down).
Just like every other class in the Foundation (except those that are broken? Which ones? I can't think of any off hand), factory methods will always return autoreleased objects and the developer should always retain the returned instance if the expectation is for the object to survive beyond the end of the current pass through the run loop.
That an NSTimer instance is retained by the NSRunLoop while it is scheduled is a part of the contract between the run loop and the timer -- by retaining the timer, the run loop is ensuring that its interaction with the timer has no bearing on the developer's interaction with the timer.
This implementation model leads to a very neat feature: If you create a scheduled one shot timer (a timer that only fires once) via NSTimer's factory methods, you don't have to even remember the returned reference to ensure that the timer will both fire and that it will be deallocated once done!
This implementation model was exactly what caused the problem in Nicholas's case. Instead of his app dieing at the bottom of the current pass through the run loop because he didn't retain the NSTimer created by the factory method, the run loop had rightfully retained the scheduled timer and the failure was pushed out further in the execution.
If Nicholas had done the same thing with an NSString-- used a factory method to create an instance, not retained the instance, messaged the instance after the current pass of the run loop-- his app would have blown up for the same reasons. The only difference is it would have been an immediate explosion as opposed to a delayed explosion.
In any case, the API was doing exactly what it is documented as doing. That retain/release/autorelease confuses developers is no surprise-- memory management has always been hard. However, being confused does not necessarily mean there is a bug in someone else's code!
(Yes-- Nicholas's post hit a bit of a button w/me... I did development support for a while and it bothers me anytime a developer blames an API for their own bug.)