15070 Views 2 Replies Latest reply: Mar 9, 2008 5:27 AM by Karl Woo
The problem is simple, when you do [Ball init] you don't instantiate Ball, but you send the message -init to a class whereas it's an instance method... Why does it work ? Well -init is defined in the root class so the Class object can execute it too... However it just returns self and does nothing else.
So here, what you do, is just retaining the Class object, that is the object that represents your Ball class.
What you want to do is to instantiate that class. You need, to do so, to use the factory methods. I think you misunderstood what +arrayWithCapacity: was doing. That method returns an allocated initialized and autoreleased objects. -init just returns an initialized objects, it doesn't allocate anything.
So before sending the init message, you have to send the alloc message to the class object to get an allocated instance that you'll then initialize using -init message, it gives you that :
Ball *ball = [[Ball alloc] init]; // no retain message
ball will contain a reference to a newly allocated and initialized instance of Ball class. And that instance will accept the -draw message, you won't get that exception.
What is important here is memory management. When you own an object you must release the object. There are 3 ways to be responsible of an object ::
// 1. With the alloc/init technique :
MyClass *obj = [[MyClass alloc] init];
// Which can be done using +new message which just make alloc/init in the same message :
MyClass *obj = [MyClass new]; // that technique is not recommanded
// 2. With the copy message :
obj = [anotherObj copy];
// 3. With the retain message :
obj = [anotherObj retain];
Each use of one of this technique must be balanced by a release or an autorelease message :
// 1. The object is deallocated immediately
// 2. The object is deallocated "later" (in AppKit apps lik your,
// it's deallocated at the end of an event loop)
In any other case, you're not responsible of releasing objects, which means that an object you get with another techniques than the 3 up there will be deallocated soon, that's why you do a -retain on your mutable array and that's why you do not have to do a retain on the ball objects for which you use alloc/init messages.
By the way, an array (mutable or not) retains the objects that are being added to it, so if you don't need the reference outside of the array you can release it.
So after adding the object to the array, release it :
Ball *ball = [[Ball alloc] init];
If you don't do that, you'll probably lose the reference to the ball object and you'll have a memory leak.
Also, the autorelease pool is useless with your draw loop.
PS : if you want to format the code beautifully like me, you simply have to use the
// your formatted code here
// your formatted code here
or the  to be transformed into what they mean (code formating, links, etc.) just put an anti-slash '\' before it.
And if you want to avoid the format specifier like the