3

In Objective C, a custom init method must call the superclass's designated initializer. Consider the following custom init method for a sublcass of NSView:

- (void)initWithFrame:(CGRect)aFrame andName:(NSString *)aName {
    if(self = [super initWithFrame:aFrame]){
        //set up object
    }
}

However, MacRuby only offers the super keyword, which simply tries calling the same method in the superclass. Since this is a custom initializer, however, the superclass has no such method.

What is the standard way of solving this? I did see this question: MacRuby custom initializers but I can't say I understand the answer very well, nor does it seem to be some broadly accepted solution. Since MacRuby is now a few years older than when that post was written, I'm hoping a clearer, standard solution now exists.

Community
  • 1
  • 1
maxedison
  • 17,243
  • 14
  • 67
  • 114

2 Answers2

4

In rubymotion (and I think MacRuby shares this behavior) there are TWO types of classes: pure Ruby, which use initialize, and classes derived from an objective-c class. It is best not to mix the two. If you are subclassing a objective-c class, you should use an init method. your initialize method will never get called!

This is because the NSObject##new method calls init, not initialize (actually even this is an oversimplification, but the abstraction works).

your example above is confusing because you are calling init instead of initWithFrame. You MUST call the designated initializer of the parent class - in this case, using super.

If the initializer you call (in this case, init, calls your initializer, you're using the wrong one - there's no escaping the recursion cycle in that case.

So you can't exactly CHOOSE which method to call on the parent. You can, however, use your own init method:

def initWithTitle(title)
  initWithFrame(CGRectZero)
  @title = title
  return self
end

I would write this method like this:

def initWithTitle(title)
  initWithFrame(CGRectZero).tap do
    @title = title
  end  # that way I never forget to return self
end
colinta
  • 3,536
  • 1
  • 28
  • 18
  • Just to be clear, you're saying that I should simply call the designated initializer on `self`, correct? Seems to make sense. – maxedison Feb 03 '13 at 01:51
  • That's right. Or from the subclass' point of view, you can either override the designated initializer and call super, or write a different initializer and call the superclass' designated initializer on self. – colinta Feb 03 '13 at 06:05
  • Thanks, makes perfect sense. In fact, I think my real confusion stemmed from never having really understood the concept of a designated initializer. You've cleared up that broader issue as well! – maxedison Feb 04 '13 at 16:22
0

If I understand you correctly, you want to create your own custom initialize method in rubymotion but still call the original init method.

I frequently do something like this:

#custom initializer
def initialize
 self.init # <--calls 'init' from parent

 #stuff happens here
end

Instead of calling super, just call the init method, this works because your object is already allocated by the time it reaches initialize. And if you have variables to pass then pass them to what ever method is considered the initializer.

(Edit: Probably need self.)

AwDogsGo2Heaven
  • 952
  • 11
  • 26
  • This doesn't seem to work if you pass parameters to the initializer. For example: https://gist.github.com/4693598 – Josh Voigts Feb 01 '13 at 19:46
  • Perhaps this is a difference between ruby motion and macruby then. I can't test yours since its not supported by rubymotion, but this is how i do other classes with no problem... maybe the 'self.' is needed?thought I feel that probably wont make a difference... – AwDogsGo2Heaven Feb 02 '13 at 02:32