views:

174

answers:

4

I am just curious if this is right, or bad practice? (i.e. using a class method to alloc/init an instance)? Also am I right in thinking that I have to release the instance in main() as its the only place I have access to the instance pointer?

// IMPLEMENTATION
+(id) newData {
    DataPoint *myNewData;
    myNewData = [[DataPoint alloc] init];
    return myNewData;
}

.

// MAIN
DataPoint *myData;
myData = [DataPoint newData];
... stuff
[myData release];

EDIT:

Also should

myNewData = [[DataPoint alloc] init];

be (or does it not matter)

myNewData = [[self alloc] init];

EDIT_002:

Strange, when I add the autorelease I get ...

alt text

EDIT_003:

@Dave DeLong, one final question, what your saying is its perferable to:

+(id) dataPoint {
    return [[[self alloc] init] autorelease];
}

rather than (where you would release in main)

+(id) new {
    return [[self alloc] init];
}

cheers gary

+2  A: 

Your static method newData is a perfectly ok practice, and you can see similar methods throughout the Cocoa API (just for example, [NSString string] and [NSData data]).

The only thing you should be doing (if you're not using the garbage collector) is adding it to an autorelease pool. The convention is that if you get a new object from alloc, new, copy, or mutableCopy, you need to retain/release it yourself. If you get an object through any other means (which your newData method would qualify as an "other means") then the assumption is that the object has been added to an autorelease pool, and there is no need to manage the memory yourself.

As for the the [DataPoint alloc] vs. [self alloc] they both compile and both work equally well from what I can tell. Coming from a Java background myself, I'd suggest the [DataPoint alloc] since you're in a static context (self being similar to the java this, shouldn't really existing in a non-static context). Granted, I'm rather new to Objective-C, and Objective-C isn't Java by any stretch, so your milage may vary.

Peter Nix
Ah I see, so add an "autorelease" in the class method and delete the [myData release]; from main.
fuzzygoat
"The convention is that if you get a new object from alloc, new, copy, or mutableCopy, you need to retain/release it yourself." - surely you only need to release it yourself; the point is that it has effectively been retained for you. On the other hand, you need to retain autoreleased objects that you want to keep hold of.
Nefrubyr
@Nefrubyr you're correct, alloc retains it implicitly and you're only responsible for releasing it. I was unintentionally ambiguous.
Peter Nix
In a static (class) method, `self` refers to the class object.
mipadi
+4  A: 

You can write it a lot neater as;

+ (id)dataPoint {
    return [[[MyDataPoint alloc] init] autorelease];
}

Note: you should still write an init method; such class methods are usually used for convenience. Also, if you don't have GC, the return value should be autoreleased in line with the Memory Management rules.

Edit renamed to +dataPoint as corrected by Dave.

Abizern
Ack, that breaks convention! Since the method contains `new`, the analyzer expects a +1 retain count.
Dave DeLong
+11  A: 

According to naming conventions, you should call it +dataPoint. The reason the analyzer is barfing at you is because (by convention), a class method that uses "new" is expected to return an object with a +1 retain count. You're returning an object with a +0 (autoreleased) retain count, and are therefore breaking convention.

As was alluded to in @Peter's answer, to create an empty object, it's usually done with [ClassName className] methods. Ex: [NSArray array], [NSData data], [NSString string], etc. So the proper thing for you to do would be to rename it [DataPoint dataPoint] and then implement it as return [[[self alloc] init] autorelease];

Using [self alloc] is preferable, since it translates down to subclasses. IE, if you create a MutableDataPoint subclass, then (if you use [self alloc]) doing [MutableDataPoint dataPoint] returns a MutableDataPoint, whereas if you leave it as [DataPoint alloc], it would come back as a DataPoint object (because that's what you're allocating). (On a side note, self refers to the object being operated on in the context of the method. For instance methods, it's the instance. For class methods, it's the Class object itself)

Edit:

If you do want the class method to return an object with a +1 retain count, then (by convention), you'd just need to call it +new (ie, DataPoint * p = [DataPoint new];). However, use of the +new method seems to have fallen into more-or-less disuse, with +alloc/-init... or a class convenience method being the favorable alternatives.

Edit #2 (Re: Edit_003):

I personally prefer the former (+dataPoint), but only because +new isn't as common and I don't have to remember to -release the object. Either one is perfectly acceptable and correct, though.

Dave DeLong
@Dave Delong, thank you very much, I was not aware that using new in that context would have that effect. Also I understand the point about using self. Much appreciated, many thanks again both to yourself and everyone who contributed.
fuzzygoat
On your third question, be aware that +[NSObject new] is defined, and it calls +alloc/-init for you, and returns an object with a +1 retain count.
Quinn Taylor
@Quinn - thanks, I forgot that it was already there! =)
Dave DeLong
@Quinn / @Dave, thank you both, I get it now.
fuzzygoat
+1  A: 

EDIT_002:

Strange, when I add the autorelease I get ...

Not strange at all. Read what it says:

  1. Method returns an Objective-C object with a +1 retain count (owning reference)

    You named your method newData. A new method returns an owning reference.

  2. Object sent -autorelease message

    Yup. Right there.

  3. Object returned to caller as owning reference (single retain count transferred to caller)

    A new method (such as newData) returns an owning reference, which means the caller of that new method receives an owning reference. The caller should own this object. Instead…

  4. Object returned to caller with a +0 (non-owning) retain count

    You autoreleased the object, negating the ownership. You're no longer returning an owning reference, even though you're supposed to. This is summed up in the last flag:

  5. Object with +0 retain counts [sic] returned to caller where a +1 (owning) retain count is expected

    The caller should expect to own the object, since it came from a new method, but it doesn't, because you autoreleased it. Because the caller thinks it owns the object, it should release or autorelease it later, but because you already did, this will be an over-release.

The solution is to obey the Cocoa naming conventions and rectify this expectation-violation. This means one of two solutions:

  1. Keep the name as it is, and don't autorelease the object.
  2. Change the name of the method so that it isn't a new method, and autorelease the object.

I'd do #2, as it's more usual and generally less work for callers.

Peter Hosey
Thank you Peter, I actually had it right the first time (purely by accident) I simply did the alloc in the method and then released in main() I now understand how this works and it makes perfect sense, I just did not realise that I had fallen foul of the naming convention and did not realise how that in turn effected the autorelease. Many thanks again for breaking down what I did wrong. Much appreciated.
fuzzygoat