views:

330

answers:

5
+2  Q: 

new on objective-c

I want to do this:

[[ClassA new] addObject:[[ClassA new] addObject:[ClassA new]]];

but the compiler returns:

"error: invalid use of void expression"

Is there a way to do it? like in java:

ClassA = new ClassA( new ClassA( new ClassA()));
A: 

In objective C, generally to create, and initialise a new object you do something along the lines of the following:

[[ClassA alloc] init]

alloc, allocates memory for the object, and init initialises it.

I don't know the details ClassA, but I'd guess you want to replace you're code with the following:

[[[ClassA alloc] init] addObject:[[[ClassA alloc] init] addObject:[[ClassA alloc] init]]]

Although taking a closer look at your java example, you seem to be passing new ClassA instances through to the constructer, the following may be more equivalent. (This assumes ClassA has a constructor called 'initWithObject'.)

ClassA *myClass = [[ClassA alloc] initWithObject:[[ClassA alloc] initWithObject:[[ClassA alloc] init]];
Tom
I think the issue stems from the fact that addObject: returns (void), rather than (ClassA *), so when he calls [[[ClassA alloc] init] addObject:[[ClassA alloc] init]], he's trying to add a (void) to a ClassA, which is obviously not right.
Tim
+2  A: 

Your code snippet will only work assuming that the new method defined on ClassA is a class method, rather than an instance method, and that ClassA also implements the addObject: selector that does what you want it to. I'm not sure how your methods are defined, but for this to work, you'd need the following method definitions on ClassA:

+ (ClassA *)new;
- (ClassA *)objectByAddingObject:(ClassA *)newObject;

The new selector would need to return a pointer to a new ClassA object, so its implementation would probably contain something similar to

return [[ClassA alloc] init];

And the addObject: selector will need to store a ClassA object within another ClassA, then return the new object with the added sub-object:

self.object = newObject;
return self;

Note that because of the nested calls to addObject:, that method has to return (ClassA *) rather than (void), as is usually the case. You might want to consider refactoring so that you're looking at something like:

[[ClassA alloc] initWithObject:[[ClassA alloc] initWithObject:[[ClassA alloc] init]]];
Tim
@Tim: I think your last point is the root of the problem. +1 from me
e.James
I would think he'd want to refactor creating 3 nested objects. Unless the fact that they're of the same class is just for simplicity in asking the question, it seems like a bad idea, and largely pointless. Perhaps specifics of the application would clarify the intent.
Quinn Taylor
A: 

edit: The following is not necessary, since new is inherited from NSObject. See Quinn Taylor's answer for details, and while you're there upvote it for being correct. :)

@interface ClassA
{
    //...
}
+(ClassA)new;
//...
@end

@implementation ClassA
+(ClassA)new { return [[ClassA alloc] init]; }
//...
@end
e.James
Whoever downvoted this: Can you please tell me what I have wrong?
e.James
I didn't downvote it, but the default +new inherited from NSObject does the alloc/init for you, no need to implement it yourself.
Quinn Taylor
The problem is really the return type of -addObject: anyway.
Quinn Taylor
@Quinn Taylor: Thank you. I didn't know that new was meant to be inherited. I'll modify my answer. As for the original question, you're right. The return type of -addObject: is the critical issue I upvoted Tim's answer for giving that reason, and I'll upvote yours as well.
e.James
+4  A: 

The real problem is that -[ClassA addObject:] very likely has a return type of void, so you can't nest that expression as the argument to the outer -addObject: call. For an example, see the documentation for -[NSMutableArray addObject:] — the method signature is - (void) addObject:(id)anObject. This can catch you off guard if you are used to different behavior in another language, particularly Java. Also note that -removeObject: returns void, not the object that was removed.

In addition, everyone is missing the point that +new is inherited unless overridden — see +[NSObject new]. However, using +new is "out of vogue", and +alloc/-init... is preferred. One reason is that since +new calls to -init anyway, you must create a +new... variant to match each -init... in the class. By that point, you get a lot of unnecessary code to solve a non-problem. I personally only use +new very rarely, and only when I know I'm only using -init.

Since you're coming from a Java background, check out this SO question if you're curious about why Objective-C uses alloc/init instead of new like Java, C++, etc.

Quinn Taylor
+2  A: 

The problem is not with new, it is with addObject, which is a void returning method.

Your code:

[[ClassA new] addObject:[[ClassA new] addObject:[ClassA new]]];

would more be equivalent to this Java code:

ClassA = new ClassA()->AddObject( new ClassA()->AddObject( new ClassA() ) );

which would fail for the same reason, that AddObject retuns void, not self.

On top of that, the code would clearly fail since new is an "ownership" method, which means you take ownership of the created object according to the memory management rules, and yet you pass it to addObject and then forget about it, so no one is left to release it. And further you don't even save a reference to the final object.

Appropriate code would be something more like:

ClassA* c2 = [ClassA classA];
[c2 addObject:[ClassA classA]];
ClassA* c = [ClassA classA];
[c addObject:c2];

where ClassA's classA method is implemented as:

(ClassA*) classA
{
    return [[ClassA new] autorelease];
}

Alternatively, you could add a further method:

(ClassA*) classAWithObject: (ClassA*) inObject
{
    ClassA* c = [ClassA classA];
    [c addObject:inObject];
    return c;
}

and then write:

ClassA* c = [ClassA classAWithObject:[ClassA classAWithObject:[ClassA classA]]];

which would be both very true to the Cocoa/Objective C way of doing it, and equivalent to your Java code, and actually obey the memory management rules.

Peter N Lewis