In Objective-C why is id used as return type for init methods? - objective-c

I did some quick searching and couldn't find an answer for this.
I'm interested to know why in Objective-C, id is used as the return type for init methods.
My guess is that it's because if the class is overridden, you don't want to return an object of the superclass's type, but I'm interested to know if it's done for some other reason.

Yup. Your idea is right on the money. A subclass should still be able to use its superclass's initialization methods and return its own type instead of the super type and returning id allows it to do that.

The superclass type idea, while a good theory, doesn't really stand up: A NSString * is a NSObject *. There's no reason it can't be referred to as such.
Instead, I think it has more to do with function signatures. In a dynamic language like Objective-C, you can have no idea what class you're messaging. But the compiler must know what type is being returned. That and Objective-C's history of convention-based programming (rather than having strict rules) means that your subclass could return a NSRect (a struct) or NSInteger (a scalar) from init. It was kooky, but valid.
C++ has a similar problem, see Is the return type part of the function signature?.
So we needed a single type for all methods with a signature of -(id)init, and id was the only thing that made sense as it specified only that the return type was an instance. That's enough for the compiler to do the right thing. Now we have instancetype, which matches the class being messaged.

In the meantime Apple added a new way to declare the return type of init methods.
It is instancetype. Read more about it e.g. here

it's possible for init to actually return an instance of a different class, so id is used. can't say i've ever seen this happen in practice, but hey :)

Related

Objective-C method overriding/overloading confusion

There seems to be some debate/disagreement on whether it is possible to 'overload' methods in Objective-C. Putting aside that it is impossible to define method overloading in Objective-C is terms equal to those of C++ (because of method signature syntax differences), I would ask in particular: Which of the following is allowed and which are not?
1) A class declaring/implementing both these methods:
- (void) doSomethingWithObject:(ClassA*) object;
- (void) doSomethingWithObject:(ClassB*) object;
2) A class declaring/implementing both these methods:
- (void) doSomethingWithObject:(ClassA*) object;
- (BOOL) doSomethingWithObject:(ClassA*) object;
3) A class declaring/implementing this method:
- (void) doSomethingWithObject:(ClassB*) object;
...when its superclass declares/implements this method:
- (void) doSomethingWithObject:(ClassA*) object;
(and the analogue for conflicting return value), both when A) ClassB descends from ClassA, and B) Not.
Question 1: no can do: Objective-C doesn't include the types in the method names; there is no mangling. It might work with Objective-C++ -- never used it that much.
Question 2: Same. Won't work.
Question 3: Will work.
EDIT: in general, method names do not include any types, so if you strip the types and they are the same then it will be considered the same, and therefore won't be allowed in the same class. Along the same lines, it WILL work if it's in different classes, although you might get some confusion if the types used in the call and the types used in what gets called don't quite agree.
You are thinking in terms of C++ where the compiler does the static binding of figuring out which instance method to call based on the type of the input.
Objective-C doesn't work that way. Instead, all binding is dynamic at run-time. Kinda like all methods being declared "virtual" in C++. The programmer is responsible for passing in appropriate variables that respond in the way your method expects.
Your method could query the object being passed in whether it responds to certain selectors and take appropriate action based on that if you wanted more robust behavior. Or your method could ask the object being passed in whether it is a type it expects. Again, this would all be done at run-time in your method. Not by the compiler.
So the answer is, declare as:
- (void) doSomethingWithObject:(id) object;
... then pass in whatever object you like.

Call method in another class by Casting?

Ok so lets say I have Class A and Class B. In Class A lets say I implemented a method called saveImage and implemented the method in the .m.
Is it simple enough to say that if I do [(ClassA*)self saveImage]; That method in Class A will get called?
What is the logic behind this and can anyone explain it so I can understand a bit better?
Thanks!
Casting is mostly just for compile-time type checking (note that for safety, it's always wise to cast when you send a message to an object of type id. See here. It's ignored by the compiler (and therefore the runtime). Casting is just a promise to the compiler that yes, that object is really is really Class A, not Class B. So if you tried to compile that, unless self is actually an instance of Class A or a subclass (as you promised), you're going to raise an exception. AKA the runtime will get mad if you break your promises :)

What is preferable in objective-c: id or explicit type?

What is better and why ?
What is better in such situations as the class init method and usual variables in a code ?
What is better and why ?
Explicit typing information is always better unless you just can't use it for some reason (see below).
It allows the compiler to much more stringently validate the code and will catch many errors at compile time that would otherwise cause your app to crash at runtime.
A long, long, time ago, everything in the APIs used id. This proved to be a complete pain in the butt; fragile and led to many crashes that would have been caught with specific types.
So, it was changed. (This was ~1994).
What is better in such situations as
the class init method and usual
variables in a code ?
For init, you have no choice but to use the generic (id) return type. Objective-C does not support either co-variant or contra-variant declarations, nor is there a mechanism for generalizing the declaration of init while also providing support for specific type checking.
Same goes for retain, objectAtIndex:, addObject: and many other methods that take or return one of many kinds of objects (or take 'em as arguments).
And, no, there is absolutely no performance difference whatsoever between id and, say, NSView*.
can you give an example when explicit
typing will cause a problem please?
If you wrote:
- (MyClass *) init;
And in a subclass:
- (MySubclass *) init;
You'd get compiler warnings out the wazoo most likely or you'd have to typecast out the wazoo.
On recent versions of clang (in Lion) you should actually not return id, and instead return instancetype. This is a keyword that is used in return types to specify that the type it returns is an instance of the class receiving the message. It is now the preferred return type for init methods on OS X Lion.
Explicit typing provides build-time protection, informing you of likely problems if you do things such as casting or performing operations on something that probably won't work.
Explicit typing also helps prevent non-obvious transfer of mistyped objects, something traveling through a path in your code you hadn't considered that turns out to be of an unexpected type. This kind of bug often doesn't become clear until the program has been tested a lot, more commonly after its release.
It's also helpful for future programmers (including your future self) trying to work with your code, making to more likely that they'll be able to tell at glance what an object is supposed to be. It makes code more "self-documenting" as a result.
Some things cannot have a meaningful type because no type actually applies. Other times you need to use id because you need to be able to accept any type of object. Cocoa Touch uses it, for example, when referring to the sender of a message because anything could have sent it; specifying an explicit type simply wouldn't work.
The vast majority of the time, though, an explicit type is to your advantage.
Use a type as specific as you can but not more so. Consider how you are using any particular variable, argument, or return type and set its type appropriately.
For example a UITableView's dataSource property is declared as id<UITableViewDataSource> because the table view only cares that its data source is some object which conforms to the UITableViewDataSource protocol. This allows the data source to be flexible enough for use with any specific class which implements the protocol but still allows the compiler to warn you if you attempt to assign an object which does not implement that protocol as the data source.
If you are too specific then your code becomes inflexible, accepting only specific implementations which are not strictly necessary (ie demanding a NSMutableString when you could really work with any NSString).
If you are too vague (typing everything as id for example) then you lose the ability to identify when you are sending unrecognized selectors to a particular instance and the compiler cannot identify any number of invalid statements.
For init methods follow the advice in The Objective-C Programming Language
The return type of an initializer method should be id.
The reason for this is that id gives an indication that the class is purposefully not considered—that the class is unspecified and subject to change, depending on context of invocation. For example, NSString provides a method initWithFormat:. When sent to an instance of NSMutableString (a subclass of NSString), however, the message returns an instance of NSMutableString, not NSString. (See also, though, the singleton example given in “Combining Allocation and Initialization.”)
I don't think there is a performance difference between both.
You can let id return type for init because you can cast the result of your init.
For exemple :
Toto *foo = [[Toto alloc] init];
id foo2 = [[Toto alloc] init];
Both work but you'll have to cast foo2 variable like that (Toto *)foo in order to access property or methods of your instance without creating a compiler warning. Even if it works fine...
I think some developers let id because they just pass there variable trough instance and don't use it. That kind of use allow to not import the .h
Regards,
KL94

Does the respondsToSelector method have to exist?

Does a method which I check for with respondsToSelector have to actually exist?
What if I only define it in the interface part and fail to implement it? I'm looking at a poor-man's virtual function in Objective-C.
First, yes the method actually has to exist for the check to succeed in the context you describe. respondsToSelector: will return NO if the method is not implemented.
More importantly, I think you mean a poor man's pure virtual function in Objective-C. All instance methods are "virtual" in Objective-C; since method lookup is done a run-time, the subclass' implementation will always be used, even from a pointer of the superclass type. In Objective-C, there is no such thing as a pure virtual base class. You can often achieve what you want by either using a #protocol to define an API or using a base class that provides an implementation that throws an NSNotImplementedException as its body. Subclasses would obviously have to override the implementation, making it effectively pure virtual.
Given that calling respondsToSelector: only makes sense when you don’t know whether a method exists, it’s not entirely clear what you mean.
If you mean, does some implementation of a method with the specified selector have to exist somewhere, the answer is no. Selectors merely represent names of methods. The #selector directive doesn’t reference any aspect of any method implementation.
respondsToSelector will return NO, since the selector isn't callable at run-time. The interface part only affects compilation.

Overriding super class methods in Objective-C

If subclass in objective-c wants to override a super class's method, does it have to match the return type too?
Yes, it must have the same selector.
update:
IIRC the arguments also needs to have the same types.
update:
It seems that all methods of the same selector needs to have equivalent types across all classes when linking dynamically, not so with static linking: linky
Yes, It be same,
But one thing to be noted is you need to pass the super-class of return types.
Eg:
-(UIScrollview)method:(id)argument;
you can return UIview as well. (simply saying super class of return types).