Question

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.

Was it helpful?

Solution

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

OTHER TIPS

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.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top