iosobjective-cnscodinginitwithcoder

super initWIthCoder return parent type?


I think I'm missing something basic...

I implemented a class with NSCoding and a child with NSCoding too, but when I call the initWithCoder of the child class , I get an InvalidArgument error.

@interface Parent: NSObject<NSCoding>;


@implementation Parent

-(id)initWithCoder:(NSCoder *)decoder {
  self = [[Parent alloc] init];

  return self;
}
@end

@interface Child: Parent<NSCoding>;


@implementation Child

-(id)initWithCoder:(NSCoder *)decoder {
  self = [super initWithCoder:decoder]; //self is Parent type here
  // self = [[Child alloc] init]; if i do that, no error but no init for the parent'attribute
  if(self){
    self.childAttribute = [decoder decodeObjectForKey:@"KeyAttribute"]; // invalide argument ==> setChildAttribute doesn't exist. 
  }
  return self;
}

I must have forgotten something basic, but I can't find out what... Anybody have an idea?

Thanks.


Solution

  • You are initializing Parent in the wrong way. When -initWithCoder: is called, the class has already been allocated. Remember the syntax:

    id myObj = [[MyClass alloc] initWithArgument:...];
    

    so it is assumed that within initializers you don't allocate, you set up default values.

    You can refer to the ObjectiveC documentation to see how this should be done. I strongly recommend to check this out: Concepts in ObjC Programming – Object Initialization.
    Also the Memory Management Guide can be very helpful. ObjectiveC relies on several conventions that you should be aware of to avoid leaks that might become difficult to track.

    The right way of initializing your parent is:

    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super init]; // it's just a subclass of NSObject
        if (self) {
            // DECODE VARIABLES...
        }
        return self;
    }
    

    If Parent were a subclass of another NSCoding-compliant class, [super init] should have been replaced by [super initWithCoder:aDecoder]; but in no case within an initializer you set self to something that has not been returned by a superclass -init... method.

    You get the error because when you call [Child alloc], an instance of Child is allocated, but then during initialization of Parent you return the Parent instance you manually allocated, therefore you lost the original reference to Child and the class does not match anymore.