开发者

Object allocation from class method?

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 a开发者_如何学Pythonlloc] 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 ...

Object allocation from class method?

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


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜