tags:

views:

68

answers:

1

I wonder if someone can explain where I am going wrong here, I am creating 2 objects (car & engine) where the car object contains a pointer to the engine object. I know I am missing the obvious or just making some silly mistake, but I can't quite put my finger on it.

NB: the code all works, except for the line that is comment ERROR.

// INTERFACE ------------------------------------------------------- **
@interface EngineClass : NSObject {
}
@end


@interface CarClass : NSObject {
    EngineClass *engine;
}
- (void)setEngine:(EngineClass *)value;
@end


// IMPLEMENT ------------------------------------------------------- **
@implementation CarClass

- (void)setEngine:(EngineClass *)newEngine {
    if (engine != newEngine) {
        [engine release];
        engine = [newEngine copy];
    }
}
@end

@implementation EngineClass
@end


// MAIN ------------------------------------------------------------ **

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    CarClass *newCar_001;
    EngineClass *newEngine_001;

    newCar_001 = [[CarClass alloc] init];
    newEngine_001 = [[EngineClass alloc] init];

    [newCar_001 setEngine: newEngine_001]; // ERROR

    // Clean up
    [newCar_001 release];
    [newEngine_001 release];
    [pool drain];
    return 0;
}
// END ------------------------------------------------------------- **

The ERROR is ....

run 2009-09-22 13:41:05.483 cocoa_engine_TEST[8606:a0f] 2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f] 2009-09-22 13:41:05.485 cocoa_engine_TEST[8606:a0f] -[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0 2009-09-22 13:41:05.486 cocoa_engine_TEST[8606:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[EngineClass copyWithZone:]: unrecognized selector sent to instance 0x10010c8d0'

cheers -gary-

+2  A: 

From the docs for the copy method:

This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is no implementation for copyWithZone:.

Have you implemented copyWithZone?

And why copy engine when you could just retain?

- (id)copyWithZone:(NSZone *)zone {
    EngineClass *engineCopy = [[EngineClass allocWithZone: zone] init];
    // copy variables here, deep or shallow
    return engineCopy;
}

It returns a retained object, as copy methods should.

Terry Wilcox
the copy came from running the "Place Accessor Defs On Clipboard" from the xcode menu using "EngineClass *engine;" As for why copy rather than retain, my understanding was that -copy ensures that if someone passes in an instance then you make a copy to work with incase the original changes? probably getting mixed up I guess ...
fuzzygoat
If there's a reason to work with a copy rather than the original, then you should use copy. You just need to remember to implement copywithZone in your EngineClass. http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Protocols/NSCopying_Protocol/Reference/Reference.html
Terry Wilcox
Hi Terry, do you have any idea how an implementation of copywithZone might look in EngineClass. I am only just learning Objective-C (3 weeks in) and it a little beyond where I am at, but I am interested to find out for future reference.
fuzzygoat
So where I am going wrong is essentially besause I am copying an instance of a class, rather then in previous examples where I was copying single variables or NSString objects.
fuzzygoat
NSString objects -are- an instance of a class. The point is that the NSString class already implements copyWithZone, but your EngineClass class does not.
andyvn22
Yes, that's where you're going wrong. As andyvn22 points out, an NSString is an instance of a class, but it already implements copyWithZone. Your EngineClass also need to implement it. How to implement it gets discussed in http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmImplementCopy.html .
Terry Wilcox
Ah I see, now I understand, can anyone expalin to a beginner how I would add that to my class (i.e. what code I would need to add)?
fuzzygoat
@fuzzygoat: You create a new object and set its state to match the original's.
Chuck
Many thanks Terry, much appreciated.
fuzzygoat