Calling a different superclass init method from custom initializer in MacRuby - objective-c

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.

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

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

Related

Is it possible to initialize a property in a category before any category method is called?

Is it possible to initialize a property in a category?
For example, if I have a mutable array property called nameList in a class. Is it possible to have a category created for this class to add an object to the array property before any of the category method is called?
If I understand you correctly, and others are interpreting your question differently, what you have is:
A class with a property
A category on that class
And you want to call a particular method automatically before any category method is called on a given instance, that method would "initialise" the category methods by modifying the property.
In other words you want the equivalent of a subclass with its init method, but using a category.
If my understanding is correct then the answer is no, there is no such thing as a category initializer. So redesign your model not to require it, which may be to just use a subclass - as that provides the behaviour you are after.
The long answer is you could have all the category methods perform a check, say by examining the property you intend to change to see if you have. If examining the property won't determine if an object has been "category initialized" then you might use an associated object (look in Apple's runtime documentation), or some other method, to record that fact.
HTH
Addendum: An even longer/more complex solution...
GCC & Clang both support a function (not method) attribute constructor which marks a function to be called at load time, the function takes no parameters and returns nothing. So for example, assume you have a class Something and a category More, then in the category implementation file, typically called Something+More.m, you can write:
__attribute__((constructor)) static void initializeSomethingMore(void)
{
// do stuff
}
(The static stops the symbol initializeSomethingMore being globally visible, you neither want to pollute the global name space or have accidental calls to this function - so you hide it.)
This function will be called automatically, much like a the standard class + (void) initialize method. What you can then do using the Objective-C runtime functions is replace the designated initializer instance methods of the class Something with your own implementations. These should first call the original implementation and then an initialize your category before returning the object. In outline you define a method like:
- (id) categoryVersionOfInit
{
self = [self categoryVersionOfInit]; // NOT a mistake, see text!
if (self)
{
// init category
}
return self;
}
and then in initializeSomethingMore switch the implementations of init and categoryVersionOfInit - so any call of init on an instance of Something actually calls categoryVersionOfInit. Now you see the reason for the apparently self-recursive call in categoryVersionOfInit - by the time it is called the implementations have been switched so the call invokes the original implementation of init... (If you're crosseyed at this point just draw a picture!)
Using this technique you can "inject" category initialization code into a class. Note that the exact point at which your initializeSomethingMore function is called is not defined, so for example you cannot assume it will be called before or after any methods your target class uses for initialization (+ initialize, + load or its own constructor functions).
Sure, it possible through objc/runtime and objc_getAssociatedObject/objc_setAssociatedObject
check this answer
No it's not possible in objective c.Category is the way to add only method to an existing class you can not add properties in to this.
Read this
Why can't I #synthesize accessors in a category?

Objective C delegates and class methods vs instance methods

There is a similar question to mine on the following link
but it doesn't quite answer my query.
I am setting a helper class for Facebook (follows the delegation pattern) . An example of one of the class methods would be:
+ (void)openSession:(id)delegate;
This method calls a the Facebook openActiveSessionWithReadPermissions method which expects a completionHandler block. Would it make sense to call the delegate method, say sessionStateChanged in the block as follows?
[delegate sessionStateChanged];
Or is it better to use instance methods for the Facebook helper class and call the delegate using [self.delegate sessionStateChanged] in the completionHandler block.
You would be better off with a block parameter rather than a delegate as a parameter if it is just for a single callback.
+ (void)openSession:(void (^)(void))sessionStateChangedBlock
That way you don't have to worry about defining a delegate protocol.
If you want to use a delegate, you will have to define a delegate variable at the class level. You can't use [self.delegate sessionStateChanged] because you are saving the delegate as a class variable. self is only available in an instance of the class.
I tried both methods i.e. using class and instance methods. Any of them will do, though to follow the proper delegation pattern I believe using instance methods is more appropriate.

Why should init parent class

I have digging in the objective-c world. One thing that I can't understand is why is necessary to call parent init method.
What purpose this ?
If you have a class and do some stuff in the init method, in case of it been inherited, you still want that stuff to happen, but now you are calling the child class init method. So unless you call the parent init the previews stuff will not happen.
same reason its necessary to call init on child classes
the init method wont be called unless its invoked
and parent classes have init methods that need invoking
as for specifics you would have to name a class NSobject, UIViewController, etc...
or look at the documentation and see if the init methods are listed
this is a slightly generic answer and id like to be more specific but IMO the question is asked "generically"

why does initializing subclasses require calling the super class's same init function?

I have heard that when you have a subclass, you are supposed to initialize the superclass with the same init function from within the subclass's init. What I mean is that the subclass's init should call [super init] and the subclass's initWithFrame should call [super initWithFrame]. Why is this? Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint? I guess the heart of the question here is simply why it's improper to call a different super class, something that's confusing me possibly because of my c++ background?
When you create a subclass, if you implement an initializer, then you must be sure to call the superclass's designated initializer(s), and you must provide at least one designated initializer of your own, though this can just be your override of the superclass's.
As part of initializing your subclass, you must call one of the superclass's designated initializers.
A class's documentation should nominate its designated initializers. If not, the designated initializer is generally assumed to be the most specific initializer (the one taking the most arguments) provided by the superclass.
For further details, see "The Objective-C Programming Language: Allocating and Initializing Objects." [Note: As of December 2013, this content no longer appears to be available via Apple's doc center. What was a language reference has been replaced by more task-oriented tutorials and conceptual documentation.]
As to your specific questions:
Why is this? So that the superclass has a chance to initialize its state. You can then go ahead and initialize the state you add above and beyond what the superclass provides.
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop? Because, for NSView, -init is not the designated initializer, though it is NSObject's. So NSView overrides it to call its designated initializer, -initWithFrame:. If you've called -init from your -initWithFrame:, you now have -initWithFrame: calling -init calling -initWithFrame: calling -init: calling…
Does this mean…? No, because this is not required. You must understand the actual documentation, not hearsay.
Why is this? Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
If the -init in super is implemented as
-(id)init {
return [self initWithFrame:CGRectZero];
}
then the call graph will loop around:
[subclass initWithFrame:]
| ^
v |
[super init]
as self always uses the current class ("subclass").
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint?
No this is not required. What is preferred is to call super's most specialized initializer, so there's no chance super's -initXXX calls back the subclass's -initYYY.
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
Coming from a C++ background as you say you do, the main problem is probably that you are used to the C++ method calling paradigm. In Objective-C, you do not call functions of objects. It's not even technically completely correct to say you invoke methods. In Objective-C, you send messages to objects and the object decides what to do with them. What it normally does is look up a method in its class and invoke that. The consequence of that is that you cannot control which version of a method in a class hierarchy gets invoked by a message. It's always the method belonging to the class of the object you send the message to (except in one case). It's as if C++ had no non virtual functions, not even the constructors.
The one exception to this is when you send a message to super. In that case, the method on your class is bypassed. This can lead to infinite loops as you have found out. The reason is because we don't call functions, we send messages. So if methodA in class SubKlass sends [super methodB] the implementation of methodB in Klass will be invoked. If it then sends [self methodA] self is still an instance of SubKlass, it hasn't magically transformed into an instance of Klass, so methodA in SubKlass will be invoked.
This is why the rules for initialisers seem so convoluted. Only the designated initialiser is guaranteed not to send one of the other initialisers so you can only safely send the designated initialiser to super in your initialiser.
from a c++ perspective:
I have heard that when you have a subclass, you are supposed to initialize the superclass with the same init function from within the subclass's init. What I mean is that the subclass's init should call [super init] and the subclass's initWithFrame should call [super initWithFrame].
that's not true. it's merely common. you are free to call any superclass initializer that is documented as a valid initializer.
it may help to view it like this:
look at the superclass' initalizers and determine which are supported.
sometimes there is a designated initializer
sometimes there are new initializers (e.g., one which may add an argument to the super-superclass)
sometimes there are intializers inherited from the super-superclass
for designated initializers: consider it protected
for new initializer: consider it protected
for inherited initializers: typically consider private when the superclass declares new initializers, otherwise protected
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
such is the effect (undefined behavior) of calling an intializer which you should not call.
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint?
this is fine as long as you call through one of the supported superclass initializers.
I guess the heart of the question here is simply why it's improper to call a different super class, something that's confusing me possibly because of my c++ background?
objc doesn't support hiding/visibility for initializers. once it's in a superclass' interface, it's there (and you're able to make bad choices where the compiler can't help you) - you're expected to determine the visibility graph for initializers and write your subclass accordingly. objc is lacking language features that you're accustomed to having in c++.
I don't know where you heard it from, but AFAIK it's not required. You can choose to init your subclass with whatever you want, provided that you call an init method of the superclass. Any init method will work.
However, if you also have the same init function in your superclass, I think the better thing to do is to call that function, then add your own customization. It's not required, it's just good practice to do so, because that init function may provide some initializations and settings that you may forget to add.

how to block a superclass method to be called to a subclass

I'm extending the functionality of a class with a subclass, and I'm doing some dirty stuff that make superclass methods dangerous (app will hang in a loop) in the context of the subclass. I know it's not a genius idea, but I'm going for the low-hanging fruit, right now it's gonna save me some time. Oh it's a dirty job, but someone's gotta do it.
Bottom line, I need to either block that method from outside, or throw an exception when it's called directly to the superclass. (But I still use it from the subclass, except with care).
What would be the best way to do this?
UPDATE ---
So this is what I went for. I'm not self-answering, as Boaz' answer mentions multiple valid ways to do this, this is just the way that suited me. In the subclass, I overrode the method like this:
- (int)dangerousMethod
{
[NSException raise:#"Danger!" format:#"Do not call send this method directly to this subclass"];
return nil;
}
I'm marking this as answered, but evidently that doesn't mean it's closed, further suggestions are welcome.
Just re-implement the unsafe method in your subclass and have it do nothing or throw an exception or re-implement it as safe, just as long as the new implementation doesn't call the unsafe superclass method.
For the C++ crew in here: Objective C doesn't let you mark methods as private. You can use its category system to split up the interface into separate files (thus hiding 'private' ones), but all methods on a class are public.
You can override whichever methods you want to block in your subclass's .h file. You can make dangerousMethod unavailable by placing the following in your .h file.
- (int)dangerousMethod __attribute__((unavailable("message")));
This will make the dangerousMethod method unavailable to anyone using your subclass.
To keep other code from using the superclass's version this method, you can further restrict by putting this in your .m file.
- (int)dangerousMethod
{
return nil;
}
note: I'm ObjC/Cocoa newcomer:
#implementation MyClass
-(void)myMethod:(NSString *)txt{
if([self class] != [MyClass class]) return;
NSLog(#"Hello");
}
#end
Peter
This article explains how to create private variables in Objective C. They aren't truly private, but from what I read, the compiler will throw a warning if you try to call them from the subclass.
If you create the methods in your superclass as "private" then the subclass has no possible way of calling them. I'm not familiar with Objective C, but every other object oriented language I've seen has the "private" qualifier.