PDA

View Full Version : Writing a Class Method




nutthick
Sep 11, 2008, 04:48 AM
I'm trying to write a class method with the following header.

@interface Point3D : NSObject
{
float pointX;
float pointY;
float pointZ;
}

+ (id)initWithPointX:(float)x Y:(float)y Z:(float)z;
- (float)x;
- (float)y;
- (float)z;

@end

and the code as follows.

+ (id)initWithPointX:(float)x Y:(float)y Z:(float)z
{
[super init];

pointX = x;
pointY = y;
pointZ = z;

return self;
}

- (float)x
{
return pointX;
}

- (float)y
{
return pointY;
}

- (float)z
{
return pointZ;
}

However, I keep getting the following warnings in the initWithPointX method

warning: instance variable 'pointX' accessed in a class method
warning: instance variable 'pointY' accessed in a class method
warning: instance variable 'pointZ' accessed in a class method

When I run the program it crashes with

The Debugger has exited due to signal 11 (SIGSEGV).The Debugger has exited due to signal 11 (SIGSEGV).

I've been Googling for a Class Method example, but can't find one. Can anyone help?

This is related to my previous post NSMutableArray and Pointers (http://forums.macrumors.com/showthread.php?t=560352) for some context.

Thanks



robbieduncan
Sep 11, 2008, 04:59 AM
1) Anything named init should not be a class method.

2) A class method cannot access instance variables: they can only be accessed by instances (they simply don't exist at the class level).

It appears you are trying to write a factory method that will return an autoreleased instance of the class. One potential solution is below:


+ (id)pointWithX:(float)x Y:(float)y Z:(float)z
{
return ([[[Point3D alloc] initWithPointX:x Y:y Z:z] autorelease]);
}

- (id)initWithPointX:(float)x Y:(float)y Z:(float)z
{
if (self = [super init])
{
pointX = x;
pointY = y;
pointZ = z;

return self;
}
return nil;
}

- (float)x
{
return pointX;
}

- (float)y
{
return pointY;
}

- (float)z
{
return pointZ;
}

gnasher729
Sep 11, 2008, 07:19 AM
[QUOTE=nutthick;6211186]I'm trying to write a class method with the following header.

@interface Point3D : NSObject
{
float pointX;
float pointY;
float pointZ;
}

+ (id)initWithPointX:(float)x Y:(float)y Z:(float)z;
- (float)x;
- (float)y;
- (float)z;

@end

and the code as follows.

+ (id)initWithPointX:(float)x Y:(float)y Z:(float)z
{
[super init];

pointX = x;
pointY = y;
pointZ = z;

return self;
}


Could you, just for yourself, try to write down as clearly as possible what a class is and what an object is and what the difference between these two is? Once you've done that, could you try to give the reasons why in every class "alloc" is a class method, while the various init methods are all instance methods?

I personally think it helps a lot if you try to understand something, and writing it down often helps with that, instead of just blundering ahead until you get something that compiles.

lee1210
Sep 11, 2008, 09:16 AM
It appears you are trying to write a factory method that will return an autoreleased instance of the class. One potential solution is below:


+ (id)pointWithX:(float)x Y:(float)y Z:(float)z
{
return ([[[Point3D alloc] initWithPointX:x Y:y Z:z] autorelease]);
}



This brings up something that I have been curious about. I just read the NSObject protocol documentation for retain, release, and autorelease, and understand that init and copy methods should return an object with a retain count of 1, and factory methods should retain an autoreleased object. What should the retain count be of the autoreleased object? 1, so when the pool calls release the retain count is 0?

-Lee

Littleodie914
Sep 11, 2008, 11:22 AM
This brings up something that I have been curious about. I just read the NSObject protocol documentation for retain, release, and autorelease, and understand that init and copy methods should return an object with a retain count of 1, and factory methods should retain an autoreleased object. What should the retain count be of the autoreleased object? 1, so when the pool calls release the retain count is 0?

-LeeI think the retain count should be 1, since you're allocating space for a new object, then initializing it.

Edit: Wait, maybe not. If you create an autoreleased object in a scope, when that scope is exited, the object is automatically autoreleased unless you specifically retain it. So I would say it's 0?

gnasher729
Sep 11, 2008, 11:38 AM
I think the retain count should be 1, since you're allocating space for a new object, then initializing it.

Edit: Wait, maybe not. If you create an autoreleased object in a scope, when that scope is exited, the object is automatically autoreleased unless you specifically retain it. So I would say it's 0?

"autorelease" doesn't release an object. It tells the active autorelease pool "please release this object when you (the autorelease pool) go out of scope". So a method creating an autoreleased object will: Call alloc (retain count = 1), call init (retain count stays = 1), call autorelease (retain count stays 1, autorelease pool will release it some time later).

So if you do nothing else, there will be another "release" call when the autorelease pool is closed down, which will change the retain count to zero and destroy the object. If you decide that you want to keep the object around for half an hour, you call retain (retain count = 2), then the autorelease pool will release it at some point in time (retain count = 1), and half an hour later your own code might release it (retain count = 0, object gets destroyed).

You can never have an object with a retain count = 0.

whooleytoo
Sep 11, 2008, 11:45 AM
and factory methods should retain an autoreleased object.

Gnasher's explanation above is correct - but I don't understand the sentence above - do you mean return, instead of retain?

Autorelease is used when returning any object from a function/method which that function/method created. And if you intend to use that object outside the calling scope, you need to retain it (and, of course, ultimately release it again when done with it).

lee1210
Sep 11, 2008, 01:07 PM
Gnasher's explanation above is correct - but I don't understand the sentence above - do you mean return, instead of retain?

Autorelease is used when returning any object from a function/method which that function/method created. And if you intend to use that object outside the calling scope, you need to retain it (and, of course, ultimately release it again when done with it).

Just at typo, i meant return. gnasher729 covered what I was curious about, which was more or less if the object returned by a factory method should have a retain count of 0 or 1.

-Lee

gnasher729
Sep 11, 2008, 04:13 PM
Gnasher's explanation above is correct - but I don't understand the sentence above - do you mean return, instead of retain?

Sometimes both :D Lets say an object that represents a window has a method returning the window title as an NSString*. Lets say the window has created that title with a retain count of 1, it keeps hold of the title and releases it when the window is deleted. You would then retain the title, autorelease it, and return the retained title. The retain count is now 2, but one retain will go away when the autorelease pool is closed. However, if you delete the window, the retain + autorelease made sure that the title survives deleting the window (until the autorelease pool releases the title).

nutthick
Sep 11, 2008, 08:20 PM
robbieduncan - Thanks for your help, I'll give it a try.