I have just started programming in Objective-C, I understand it only partially supports method overloading due to the way the method names are generated (see this question).
However, my question is why I have never seen it used in any examples. The code below seems to work fine, but any sort of example I have seen, the second init would be named initWithServerName or something like that, instead of taking advantage of the overloading.
-(id) init {
self = [super init];
return self;
}
// usually this would be called initWithName or something? but to me it
// seems easier this way because it reminds me of method overloading from C#.
-(id) init: (NSString*)newServerName {
self = [super init];
if(self) {
serverName = [[NSString alloc] initWithString:newServerName];
}
return self;
}
What is the reason for this? Does it cause problems in sub-classes to name methods this way?
Unlike Algol-style languages like C#, Objective-C's syntax is specifically designed for literate method names. init: tells me nothing about the method parameter. Is the receiver initing the thing I'm passing? No. It's using the argument in some way, so we use a descriptive name like initWithFormat: to specify that the argument is a format string.
Also, Objective-C does not have method overloading at all. Period. A single selector for a given class can only have one type signature. The only way to change behavior based on an argument's class is to have a method take a generic type that could include many different classes (like id or NSObject*), ask the argument for its class and do different things depending on the result of that query.
That's not the same method. In objective-C a selector named init is different than one named init:. The colon is part of the selector name.
Also, init is overridden fairly often, you just have the wrong method.
Aside from jer's answer, it also does not allow you to specify multiple ways to initialise an instance. For example, NSString has initWithString:, initWithFormat:, etc.
Related
I'm just trying to learn objectives-c.
I've seen wikipedia example for AbstractFactory pattern, across different languages.
Here's the Button definition:
#protocol Button
- (void)paint;
#end
#interface WinButton : NSObject <Button>
#end
Here's a factory:
#implementation WinFactory
- (id)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
As far as I kwnow, obj-c's id keyword should be something like C#'s var or C++11's auto,
right?
So I my question is:
why let the factory return a generic object of a not specified type?
Is this an error (that let factory return something other that is not a Button) or is there any reason to do that?
I'd write a factory this way:
#implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
am I wrong?
why let the factory return a generic object of a not specified type?
In many cases where you see id returned, it is because they are not consistently typed (really abstract objects), or it is because an implicit upcast would have been introduced.
Is this an error (that let factory return something other that is not a Button) or is there any reason to do that?
It is not an error. Of course, you should not return a type which does not match.
I'd write a factory this way:… am I wrong?
#implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
#end
The big gotcha in this scenario is that ObjC is quite loosely typed, and you should strive to ensure all selectors' parameters and return types match. That is to say, every createButton in all your translations should all return the same type and have the same types for parameters. Sometimes you will have to choose a more descriptive name in order to avoid ambiguity for the compiler.
That ought to explain why +[NSString string] returns id -- if it returned NSString, then +[NSMutableString string] could be a source of warnings. This is because the compiler can have a difficult (impossible) time matching a method declaration to a dynamic instance. That may also help you understand the 'wordy' naming of selectors, such as convenience constructors which also contain the type in the method (e.g. +[NSDictionary dictionaryWithObject:] as opposed to simply +[NSDictionary withObject:]).
But to get to your question: id<Button> or NSObject<Button>* or some other qualified type is just fine -- as long as you can live with that common method signature. You're introducing type-qualification, which helps the compiler help you.
The more correct return type here would be :
- (id<Button>)createButton;
This means that the returned type is an object that conforms to the <Button> protocol. I may fix up the WP page just to be a little more clear. The <Button> protocol should also inherit from the <NSObject> protocol for completeness (and to simplify actual usage).
Note that the Abstract Factory pattern is somewhat unusual in ObjC. I'm trying to think of a case where it's used in UIKit or Foundation. It's more common for the class to handle this internally (such as in NSNumber) and is called a class cluster.
Be very careful of trying to code in a C++ or C# style in ObjC. ObjC is not a static language, and the patterns used are often quite different. (I'm not saying that AF is a static pattern. It could be used quite well in ObjC. I'm just saying that the fact that you're looking at it while trying to learn ObjC means that you may be approaching it backwards, learning "how do I do this C++ in ObjC" rather than learning "how do I develop in ObjC.")
Objective-C has the concept of class clusters, which are abstract factories.
See this answer.
I am in a situation where I want to dynamically generate getters and setters for a class at runtime (in a similar manner to what NSManagedObject does behind the scenes). From my understanding, this is possible using resolveInstanceMethod: on a specific class. At this point, you would have to use class_addMethod to dynamically add the method based on the selector. I understand this at a theoretical level, but I haven't delved much into the obj-c runtime, so I was curious if there were any great examples of how to do this. Most of my knowledge comes from this article:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html
Any thoughts / examples?
The only nice discussion I know is at Mike Ash's blog post. It's not that hard, actually.
I once needed to split a big NSManagedObject subclass into two, but decided to keep the fact an implementation detail so that I don't have to rewrite other parts of my app. So, I needed to synthesize getter and setter which sends [self foo] to [self.data foo], automatically.
To achieve that, I did the following:
Prepare the new method, already in my class.
- (id)_getter_
{
return objc_msgSend(self.data, _cmd);
}
- (void)_setter_:(id)value
{
objc_msgSend(self.data, _cmd,value);
}
Note that _cmd has the selector in it. So, usually, _cmd is either #selector(_getter_) or #selector(_setter_) in these methods, but I'm going to plug the implementation of _getter_ as the implementation of foo. Then, _cmd contains #selector(foo), and thus calls self.data's foo.
Write a generic synthesizing method:
+(void)synthesizeForwarder:(NSString*)getterName
{
NSString*setterName=[NSString stringWithFormat:#"set%#%#:",
[[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
Method getter=class_getInstanceMethod(self, #selector(_getter_));
class_addMethod(self, NSSelectorFromString(getterName),
method_getImplementation(getter), method_getTypeEncoding(getter));
Method setter=class_getInstanceMethod(self, #selector(_setter_:));
class_addMethod(self, NSSelectorFromString(setterName),
method_getImplementation(setter), method_getTypeEncoding(setter));
}
Note that this is a class method. So self stands for the class. Note also that I didn't hardcode type encodings (which tells Objective-C runtime what the arguments of the particular method are). The syntax of type encodings is documented, but constructing by hand is very error-prone; I wasted a few days that way until Mike Ash told me to stop it. Generate it using an existing method.
Generate forwarders at the earliest possible time:
+(void)load
{
for(NSString*selectorName in [NSArray arrayWithObjects:#"foo", #"bar", #"baz",nil]){
[self synthesizeForwarder:selectorName];
}
}
This generates foo, setFoo:, bar, setBar:, and baz, setBaz:.
Hope this helps!
Another example is one I wrote, called DynamicStorage, available here:
https://github.com/davedelong/Demos
The primary impetus behind it was this question, which was asking how to use an NSMutableDictionary as the backing store for any object ivar. I wrote a class that will generate getters and setters for any #property, respecting things like a custom getter/setter name, the object memory management policy, etc. The neat thing about it is that it's using imp_implementationWithBlock() so that it only has to calculate the appropriate property name once (and then captures and saves it as part of the block).
I have a question about writing your own init methods in objective-c. I've read a few different books and have seen a couple of ways to do it but the consensus is the right way to do it is like this:
- (id)init
{
self = [super init];
if(self!=nil)
{
}
return self;
}
I'm a little confused about the line "self = [super init]". My understanding is that, there's no guarantee that [super init] will return the class that you expect it to. I think this is called "class clusters". But in the normal case, where it does return the class you expect it to, if I set self to point to a class that is returned to me, aren't I just saying that self is referring to an object of a different class rather than the class that I'm in the init method of?
To summarize, why set self to be the superclass vs the actual class I'm in?
From a blog I read:
The textbook reason is because [super
init] is permitted to do one of three
things:
1) Return its own receiver (the self
pointer doesn't change) with inherited
instance values initialized. 2) Return a
different object with inherited
instance values initialized. 3) Return
nil, indicating failure. In the first
case, the assignment has no effect on
self...
"The assignment has no effect on self" is what confuses me. Why does it have no effect? If I set something = to something else, shouldn't that have an effect?
There are different opinions on the proper way to write -init methods. There are two reasons that would make you think that self = [super init] is a good idea. (The assignment itself isn't anything special; Objective-C considers self to be a hidden parameter of the method, and you can reassign to parameters. The changed self only applies for the remainder of the method.)
Superclass -init returns instance of different class
As you suggested, some classes use the "class cluster" pattern. However, in the most common implementation of this pattern, it's the -alloc method on the base class that is likely to return an instance of a different class, and it's all the -init... methods on the placeholder class that are likely to return an instance of a different class. self = [super init] is not useful here.
Superclass -init returns a different instance of the same class
This is the reason that self = [super init] is recommended. Some classes have logic that allows -init to return a different instance than the one that it was called on. For example, some singleton classes in the Cocoa framework do this. But in almost every case, you need to know this behavior of the superclass in order to properly subclass it. Here's an argument by Wil Shipley that self = [super init] isn't actually very useful, because either [super init] returns self anyway, or the class you're subclassing is sufficiently complicated that reassigning self and then continuing with the initialization won't work anyway.
To summarize, why set self to be the superclass vs the actual class I'm in?
This is the Apple suggested way to do things, specifically due to the case of class clusters, as you say.
In general, you should not worry about the fact that self might be of a different class in the "normal" case.
self simply identifies the object you are, not the class (the class is actually a different object in the runtime). If you think of OO inheritance properties, it is at the same time an object of its class and of its superclass (if it is clear what I am trying to say). There is no contradiction in the "normal" case, since the value of self does not change.
Also, you can think of self as a special pointer to your object. In the cluster case, self can change, that is the reason why it can happen that its class change.
Hope this helps clarifying things. You will also find an interesting reading in this article by Wil Shipley.
// A : Parent
#implementation A
-(id) init
{
// change self here then return it
}
#end A
A *a = [[A alloc] init];
a. Just wondering, if self is a local variable or global? If it's local then what is the point of self = [super init] in init? I can successfully define some local variable and use like this, why would I need to assign it to self.
-(id) init
{
id tmp = [super init];
if(tmp != nil) {
//do stuff
}
return tmp;
}
b. If [super init] returns some other object instance and I have to overwrite self then I will not be able to access A's methods any more, since it will be completely new object? Am I right?
c. super and self pointing to the same memory and the major difference between them is method lookup order. Am I right?
sorry, don't have Mac to try, learning theory as for now...
Dreamlax's answer is correct... but, clarification may be helpful.
a. Just wondering, if self is a local
variable or global? If it's local then
what is the point of self = [super
init] in init? I can successfully
define some local variable and use
like this, why would I need to assign
it to self.
self is not a local variable. It is an argument to the method call. The first argument, in fact. The second argument is _cmd, the name of the selector of the method being executed.
What is special about self is that self is used by the compiler to access instance variables. That is, if you say self = [super init] and the superclass's init happens to return something different, any further instance variable accesses will still be correct.
b. If [super init] returns some other
object instance and I have to
overwrite self then I will not be able
to access A's methods any more, since
it will be completely new object? Am I
right?
If super's init returns an instance of something that is incompatible with A, then something has gone horribly awry in the design of the superclass. Keep in mind that Objective-C is fully dynamic. Thus, there is no reason that whatever is returned by super's init actually needs to be an instance of A, but it better had damned well act like an A. Now, it could be a completely new instance of a subclass of A and, thus, all of the methods of A will work just fine.
Reading between the lines; remember that Objective-C is fully dynamic. There is no such thing as static method dispatch. The class of an object could change at any time and any random method call will still work as long as the new class responds to the method. Not that this actually happens at runtime, just that it could.
c. super and self pointing to the same
memory and the major difference
between them is method lookup order.
Am I right?
Now, this is the fun question. super doesn't really point to anything. For all intents and purposes, super can be treated as the one bit of magic in this. That is, when the compiler sees super as the target of a method call, it compiles it as a slightly different call site that calls through to one of the variants of objc_msgSendSuper() which -- as name implies -- effectively "searches" for the method's implementation starting in the parent class of the class within which the call was compiled.
Self is an argument provided to the method implementation. All Objective-C instance and class methods have two implicit arguments that precede the method's arguments. The implicit arguments are self and _cmd. _cmd is the selector used to determine the method implementation.
If super returns an instance of a different class, then that would be the case, but it is also possible that it may return a different instance of the same class.
super is a keyword, not a variable. It informs the compiler to use a different runtime function that begins method resolution at one class higher than the current class.
In my code, I have something that looks like this:
#implementation MyClass
- (id) initWithType:(NSInteger)type {
[self release];
if (type == 0) {
self = [[MyClassSubclass1 alloc] init];
} else {
self = [[MyClassSubclass2 alloc] init];
}
return self;
}
//...
#end
which I think handles any potential memory leaks. However, I have seen code out there that does something similar, except it doesn't release self before reassigning it to another newly allocated instance. Is it not necessary to release self here or is the other code I've seen incorrect?
Your code looks technically correct, from a memory management perspective. Replacing self with a different alloc'd object loses the pointer to the original object, and nobody else will be able to release it, which would cause a leak. Try commenting out the release call and run it with Leaks in Instruments.
Just be cautious about opening this particular can of worms — Foundation.framework (part of Cocoa) uses class clusters for collections and strings, but doing so is a fairly advanced concept. A better approach might be to have a class method for each subclass, using the AbstractFactory pattern.
In any case, determining the subclass type based on an integer is a bad idea — any change in mapping from type to class will break dependent code. If you're going that way, why not just pass in the class object itself?
This looks like poor use of object-oriented design.
If you're creating a different instance depending on a type variable, then why don't you have subclasses for those types?
It would be much cleaner to define a base class with all the common functionality, and a subclass for each "type" variation.
What does the class do? We might be able to point you in the right direction.
Code-wise, your example code is correct, but it's generally bad practice to replace the instance with a different instance. Unless the init method is a factory method re-using instances or a singleton initializer, avoid releasing self en-lieu of another instance.