Can pointers of one class contain extended classes without problems? - objective-c

I am newish to Objective-C. I am trying to determine if having a pointer for one class, then assigning an extended class to that pointer instead, will cause problems. For instance if ClassB extends ClassA, and I do this:
ClassA *foo = [[ClassB alloc] init];
Will this cause problems somewhere down the line? I know that Xcode seems to be okay with it, but that doesn't mean it is okay.

Yes, that's called polymorphism, you can do it without problems.
However since in Objective-C the message dispatching is dynamic, if the class B contains an overridden method, this one will be executed. This is often used when you know you'll receive an object of a class that inherits from a known base class, but you don't know which one. You can turn this to your advantage.

Related

Why can I call a subclass method with a superclass pointer in Objective-C?

I have two classes, Food and Nacho. Food is Nacho's super class.
Food *junk = [[Nacho alloc] init];
is valid as long as I call Food's methods, right?
But how come that Food pointer can call one of Nacho's methods (which is defined as an additional method in the subclass)?
fixed , removed 'NS' prefix from class name.
Well, it isn't really an NSMom instance, so you can call it at runtime because the NSSon instance does implement the method. At compile time you do need to do something to tell the compiler that it shouldn't check the type (or that it should trust you).
Aside - don't prefix your own classes with 'NS' in real code. Sooner or later you'll get a clash with an Apple class.

Is it an acceptable pattern for an init method to return an object of a different type?

I'm working on bugfixes for some existing objective-c code and came across something I thought strange:
#interface ClassA : UIView
...
static ClassA* oldSelf = nil;
#implementation
- (id)initWithFrame:(CGRect)frame {
oldSelf = self;
self = [[ClassB alloc] initWithFrame:(CGRect)frame]; // xcode warns: Incompatible pointer types assigning to "ClassA *" from "ClassB *"
// ^^^^^^ Is this ok?
[oldSelf release];
return self;
}
#interface ClassB : UIView
...
#implementation
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
return self;
}
This whole thing is wrapped up into a static library. The public gets the lib.a file and ClassA.h
In code using the library, This occurs:
#import "ClassA.h"
...
// useage
ClassA *myA = [[ClassA alloc] initiWithFrame:CGRectMake(0,0,100,100)];
...
So we got an initializer for ClassA that actually returns an unrelated class. ClassA and ClassB respond to the same messages so it compiles and runs. Seems like ClassA is being used to obscure some features exposed in ClassB?
I'm curious if this is acceptable behavior, and if it's a known pattern, what is it called? Are there any side effects to this setup?
=========================================================
Thanks for everyone's answers! I think I've got it... in short, not a normal pattern, and not exactly a good idea
Kind of like a "class cluster"(abstract factory), but not quite, because a common abstract class should be returned. And since the code doesn't seem to ever intend to return anything but a ClassB object, probably not what the original author was thinking.
More like a proxy, but implemented wrong. ClassA should hold a private instance of ClassB and pass messages between the two.
=========================================================
Edited: added "oldSelf" parts...
Edited: added static library details...
Edited: added a blurb about the accepted answer...
The major disadvantage I see here is: a user of ClassA would expect that an object he just created via [[ClassA alloc] initWithFrame:...] returns YES for [object isKindOfClass:[ClassA class].
This might also lead to errors when using things like NSInvocation, because the wrong class would be used to determine the method signature, though I am not sure about that.
Due to Objective-Cs dynamic nature, this will, as you described, work, but may be confusing to use and i would strongly discourage anyone from using this pattern.
As pilavdzice said, the "right" alternative to this would be to have both ClassAand ClassB inherit from another class (an abstact superclass) which then in its initializer decides what concrete subclass to use. Good examples of this pattern, called class clusters, are NSString, NSArray and NSDictionary which all return objects of various subclasses based on how you initialize them, which is also the reason you can not subclass those directly without some effort.
It's not an unreasonable thing to do in all cases, but it's hard to say whether it's a good idea in the situation you describe. Two examples where it might be fine:
The initializer returns an instance of a more specialized subclass. For example, you might choose different implementations of a data structure depending on the number of items being stored.
The initializer returns some sort of proxy object.
Your code does seem a bit odd. At the very least, I'd expect to see a cast as a signal (both to the compiler and to future programmers) that the author knew what he was doing. A comment explaining the reason for returning a different type of object wouldn't hurt, either. Ideally, ClassB should be a subclass of ClassA since it's expected to provide the same interface.
Class clusters are implemented in this way, sort-of. A related technique, isa-swizzling can be used to implement a sort of state machine. It does require the same ivar layout to work. In terms of side effects, I believe that it may break KVO; but someone may correct me on that point.
It's certainly not common in user code to return an unrelated class, however it is common in some of Apple's frameworks to return a more specific version of a class with the same public interface.
Apple's Cocoa Fundamentals discusses in some amount of detail the fact that objects such as NSArray and NSNumber may return a different object than the class you are asking for.
That isn't a pattern I know of.
If I am understanding this correctly, the normal way to do this would be to have both classes inherit from the same abstract base class.
As #alan duncun notes, this technique is called a class cluster and is somewhat common. But your implementation is slightly incorrect. You should never return a incompatible type. In your example, ClassB should inherit from ClassA.
Well this is somewhat how NSScanner is implemented.
This way the inner class is not exposed and can not be misused. ClassB can not be initialized somewhere else other than in the implementation file of ClassA.
This makes sense if you have multiple inner classes and your initializer somehow decides which class is actually needed.
I don't see any advantages if you only use one inner class.

Objective C - preferred way to create and initialize an object

Is one of these two ways to create and initialize an object preferable?
MyClass oClass = [[MyClass alloc] init];
oClass.length = 5;
oClass.text = #"Hello";
or using a class method that contains about the same code but looks like this:
MyClass oClass = [MyClass myClassWithLength:(int) 5 andText:(NSString *) #"Hello"];
I hate it when I see things done more than one way and I have no idea if one is better than the other, or why!
Don't be a hater. :-)
By the way, I'm assuming you meant:
(Edit: removed unnecessary casts)
MyClass oClass = [[MyClass alloc] initWithLength:5 andText:#"Hello"];
The reason for multiple init... methods is to make it more convenient for developers to create properly initialized instances. So, for example, if you find that developers often need to create instances of MyClass with a length and text, you make their life easier by providing an API that allows them to do that in one step. And if you find that developers also frequently need to create instances of MyClass with just a text string, you might also provide an -initWithText: method.
And if the instances created this way are frequently used as temporary objects (i.e., not stored in instance variables or static variables), you might also add a class convenience method like +myClassWithText: that returns an autoreleased instance of MyClass initialized with the provided text string.
As to which one is better: it's always better to fully initialize an object when possible, so if the object needs both values to be properly initialized, use the method that allows you to provide both arguments. And if you don't need to store a reference to the instance you're creating, use the class convenience method so your code doesn't have to deal with memory management.
If the object is unusable without the length and text, then the second option might be better. If those fields are optional, then the first one is better.
However, I don't think there is absolute truth to this question.
If you have a class with many properties it's very unlikely to initialize them all in one single line of code. Both ways work fine for me.
If an initWithSomething: method is available and you want to provide initial values for those properties, I would always prefer it just because it's simpler. It also will always work even with immutable versions of a class.
But neither init method is inherently "better." Classes usually have one or two designated initializers and all the others just call those with default values — it doesn't necessarily leave the instance's properties untouched. The documentation for a class should indicate what its initializers do and which is the designated initializer for the class. For example, [[NSDate alloc] init] uses NSDate's designated initializer, initWithTimeIntervalSinceReferenceDate:, to create a date object representing the current date and time.
Incidentally, this also means that when you're subclassing a class, you only need to override its designated initializer. Since the others just call that, they get your new behavior for free.

How does inheriting from NSObject work?

There are a couple of things about Objective-C that are confusing to me:
Firstly, in the objective-c guide, it is very clear that each class needs to call the init method of its subclass. It's a little bit unclear about whether or not a class that inherits directly from NSObject needs to call its init method. Is this the case? And if so, why is that?
Secondly, in the section about NSObject, there's this warning:
A class that doesn’t need to inherit any special behavior from another class should nevertheless be made a subclass of the NSObject class. Instances of the class must at least have the ability to behave like Objective-C objects at runtime. Inheriting this ability from the NSObject class is much simpler and much more reliable than reinventing it in a new class definition.
Does this mean that I need to specify that all objects inherit from NSObject explicitly? Or is this like Java/Python/C# where all classes are subtypes of NSObject? If not, is there any reason to make a root class other than NSObject?
1) Any time an object is allocated in Objective-C its memory is zeroed out, and must be initialized by a call to init. Subclasses of NSObject may have their own specialized init routines, and at the beginning of such they should call their superclass' init routine something like so:
self = [super init];
The idea being that all init routines eventually trickle up to NSObject's init.
2) You need to be explicit about the inheritance:
#instance myClass : NSObject { /*...*/ } #end
There is no reason to have a root class other than NSObject -- a lot of Objective-C relies heavily on this class, so trying to circumvent it will result in you needlessly shooting yourself in the foot.
Since it is possible to inherit from different root base classes, yes you must explicitly declare you inherit from NSObject when you make any new class (unless of course you are subclassing something else already, which itself in turn probably subclasses NSObject).
Almost never is there a need to make your own base class, nor would it be easy to do so.
Objective-C can have multiple root classes, so you need to be explicit about inheritance. IIRC NSProxy is another root class. You'll likely never want or need to create your own root class, but they do exist.
As for calling NSObject's init, it's part custom and part safety. NSObject's init may not do anything now, that's no guarantee that future behaviour won't change. Call init to be safe.
You need to call [super init] because there is code behind initializing that you dont have to write because it is written for you in NSObjects init, such as probably actual memory allocation etc.

I need a good analogy to make sense of Class methods vs. instance methods

Im getting fairly confused as the book im reading is delving into the NSNumber class and talks about all the different methods you can call on it. I have a couple questions:
1.) Do you not have to call a typical alloc or init on foundation classes?
2.)in what cases would you use, say, numberWithChar: as opposed to initWithChar (i think this is the part that is messing me up the most, not really sure im groking this concept on the level i need to be, if you folks could break it down for me I think it would really help me get over this humper-roo.
Thanks,
Nick
Class/Instance Analogies
Classes are like blueprints for a type house. Instances are like actual houses. So you can only have one blueprint for a single type of house, but you can have multiple actual houses of the same type. Also, you can have multiple blueprints, and each blueprint describes a different type of house.
Another analogy you can use is that classes are like cookie cutters, and instances are like cookies made from a cookie cutter.
How It Applies To Objective-C
There is one "class object" for every class in your code. To refer to the class object, you just use the class name. alloc is a class method that allocates a new instance like so:
MyWidget* w = [MyWidget alloc];
However, alloc doesn't initialize the class, so none of the member variables will be set up. init is an instance method that will initialize a newly allocated instance. So to allocate and initialize a new instance, you do this:
MyWidget* w = [[MyWidget alloc] init];
Which is equivalent to this:
MyWidget* w = [MyWidget alloc]; //alloc is being called on the class
w = [w init]; //init is being called on the instance
Another common type of class method is a factory method like numberWithChar:. This is basically what numberWithChar: does:
+(NSNumber*) numberWithChar:(char)c;
{
return [[[NSNumber alloc] initWithChar:c] autorelease];
}
The only real difference is that numberWithChar: returns an autoreleased object.
All objects must be allocated and initialized. That includes foundation classes.
1) alloc and init need to be called virtually always. numberWithChar is a convenience method, which means it calls alloc, init, and autorelease for you and returns the autoreleased instance.
2) Since numberWithChar returns an autoreleased object, that means unless you retain it (or pass it to something like an NSArray which will retain it), it'll be destroyed shortly. initWithChar returns a retain-ed object, which means you have to release it when you're done with it.
I found when I was starting out that it was helpful to use init-alloc as a rule, instead of the convenience methods, because it made me pay close attention to my memory management.
The difference between class and instance methods is addressed from a number of angles in the answers to this question What is the difference between class and instance methods?
EDIT:
To be honest, the analogy I use when I call a class method on, say NSString, is praying to the god of NSStrings to bestow upon me a magnificent new NSString. Notice that class methods are almost 100% used for creation. e.g. alloc is a class method, stringWithFormat is a class method, and so on.
Yes, it's ridiculous, I know.
Ok, first thing: In Objective-C, you don't call a method, you send a message to an object. The runtime looks up the methods and calls them.
It might help you to think of a class as a factory. In fact, years ago, we used to refer to class methods as factory methods.