Search code examples
iosobjective-cstack-overflowobject-initialization

Objective-C call specific class method


I have a class that has this in the initializer:

@implementation BaseFooClass

-(id) init
{
     if (self = [super init])
     {
          // initialize instance variables that always need to start with this value
     }

     return self;
}

-(id) initWithSomeInt:(int) someInt
{
     if (self = [self init]) // <-- I need to make sure that I am calling BaseFooClass's init here, not SubFooClass's, does that make sense?
     {
          self.someInt = someInt;
     }

     return self;
}

@end

That is all fine and dandy. My problem is that when I implement the subclass:

@implementation SubFooClass

-(id) init
{
     return [self initWithSomeInt:0];
}

-(id) initWithSomeInt:(int) someInt
{

     if (self = [super init]) // <--- Infinite loop (stack overflow :) )
     {
          // initialize other variables
     }
}

@end

I basically need to specifically call the BaseFooClass's init rather than the SubFooClass's init.

I cannot change the way the objects are initialized, as I am converting a project from C# to use in my iPad application.

Thank you all in advance

EDIT:

Due to someone asking, here is my header:

@interface BaseFooClass : NSObject

// implicit from NSObject
// -(id) init;

-(id) initWithSomeInt:(int) someInt;

// more methods

@end

@interface SubFooClass : BaseFooClass

// implicit from NSObject
// -(id) init;

// implicit from BaseFooClass
//-(id) initWithSomeInt:(int) someInt;


@end

Solution

  • Objective-C doesn't work this way because of the way the runtime converts methods into function calls. Self is always an instance of the allocated class, even when invoking the super-class's methods. You need to create your designated initializer for your BaseClassFoo and always go there. So you should be doing something like this:

    @implementation BaseFooClass
    
    -(id) init
    {
      return [self initWithSomeInt:0]; // redirect super class's designated initializer
    }
    
    -(id) initWithSomeInt:(int) someInt
    {
      if ((self = [super init])) // Designated initializer always calls into super class's designated initializer (in this case, NSObject's designated initializer is init
      {
        self.someInt = someInt;
      }
    
      return self;
    }
    
    @end
    
    @implementation SubFooClass
    
    // Here we don't override init because our super class's designated initializer
    // is initWithSomeInt:
    // -(id) init
    // {
    //   return [self initWithSomeInt:0];
    // }
    
    // we override this because it's our superclass's designated initializer, plus it
    // is ours as well
    -(id) initWithSomeInt:(int) someInt
    {
      if ((self = [super initWithSomeInt:someInt]))
      {
        // initialize other sub-class specific variables
      }
    }
    
    @end