How does inheriting from NSObject work? - objective-c

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.

Related

Why does registering a subclass with its superclass in +initialize present a chicken and egg issue? (objc)

Just reading an excerpt from this website.
Because +initialize runs lazily, it's obviously not a good place to
put code to register a class that otherwise wouldn't get used. For
example, NSValueTransformer or NSURLProtocol subclasses can't use
+initialize to register themselves with their superclasses, because you set up a chicken-and-egg situation.
I understand that +initialize is run once per class when the first message is sent to that class. Also, if any of the subclasses do not implement their own +initialize, the +initialize method will be run again in the superclass.
I am just not 100% on why registering a subclass with its superclass in its own +initialize method would present a chicken and egg problem.
Is it because the superclass may have never had its +initialize invoked, and you are trying to register your subclass with its superclass in a method that depends on the superclass calling its +initialize first?
Just a little bit of further clarification would go a long way for me, thank you.
Take the example of NSURLProtocol. The way it's used is that registered subclasses are asked, in turn, if they can handle a request. The first to answer yes gets an instance created and the request is handed off.
The initialize method is only called if a message is sent to the class. Since only registered subclasses are asked to handle a request, you can't register in initialize because it won't ever be invoked.
Two extracts from the documentation on the initialize method:
The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses.
...
Because initialize is called in a thread-safe manner and the order of initialize being called on different classes is not guaranteed, it’s important to do the minimum amount of work necessary in initialize methods. Specifically, any code that takes locks that might be required by other classes in their initialize methods is liable to lead to deadlocks. Therefore you should not rely on initialize for complex initialization, and should instead limit it to straightforward, class local initialization.
The initialize message is sent to a class the first time the runtime encounters it, for example the first time you need to allocate that class or the first time you access its sharedInstance method (in case of a singleton), and it acquires some locks in order to guarantee the thread safety. If you make references to subclasses from within this method, you can get into a deadlock situation, as both the base class and the subclass will lock onto the same thing.
For example, let's consider the scenario of a superclass MyClass and one of it's children MySubclass:
#interface MyClass
#end
#interface MySubclass: MyClass
#end
#implementation MyClass
+ (void)initialize {
[MySubclass doSomething];
}
When the runtime encounters the first usage of MyClass, it acquires a lock, and calls the class method initialize. Now, when executing the method it realises that this is also the first time it encounters MySubclass, and must also intialize it before the class can do some actual work. And what does this trigger? Yes, you've guessed, another call to +[MyClass initialize].
This how we end up in the chicken-egg situation, or to put it more technical - the deadlock, or the recursion. MyClass calls on MySubclass, this means that MySubclass needs to be initialized before MyClass is used. However MySubclass is a child of MyClass, so MyClass should be initialized first. So, which one the two should be first initialized?

Implementation of -init vs. +initialize

Can anyone explain why we need to include if (self == SomeClass class) inside the +initialize method?
I’ve found similar questions (listed below), but didn’t find any specific clarifications:
Objective-C: init vs initialize
Should +initialize/+load always start with an: if (self == [MyClass class]) guard?
Everyone says that if you don’t implement/override +initialize in Subclass, then it’s going to call the parent class twice.
Can anyone explain that part in particular, specifically why does it call the parent class twice?
Lastly, why doesn’t it happen when we implement +initialize in the class that inherits from NSObject, where we create a custom -init method and call self = [super init];.
Imagine you have a superclass that implements +initialize and a subclass that does not.
#interface SuperClass : NSObject #end
#implementation SuperClass
+(void)initialize {
NSLog(#"This is class %# running SuperClass +initialize", self);
}
#end
#interface SubClass : SuperClass #end
#implementation SubClass
// no +initialize implementation
#end
Use the superclass. This provokes a call to +[SuperClass initialize].
[SuperClass class];
=> This is class SuperClass running SuperClass +initialize
Now use the subclass. The runtime looks for an implementation of +initialize in SubClass and does not find anything. Then it looks for an inherited implementation in SuperClass and finds it. The inherited implementation gets called even though it was already called once on behalf of SuperClass itself:
[SubClass class];
=> This is class SubClass running SuperClass +initialize
The guard allows you to perform work that must be run at most once. Any subsequent calls to +initialize have a different class as self, so the guard can ignore them.
-init and +initialize are completely different things. The first is for initializing instances; the second is for initializing classes.
The first time any given class is messaged, the runtime makes sure to invoke +initialize on it and its superclasses. The superclasses are initialized first because they need to be ready before any subclass can initialize itself.
So, the first that time YourSubclass is messaged, the runtime might do something like:
[NSObject initialize];
[YourClass initialize];
[YourSubclass initialize];
(Although it's very unlikely that this would be the first time that NSObject is messaged, so probably it doesn't need to be initialized at this point. It's just for illustration.)
If YourSubclass doesn't implement +initialize, then the [YourSubclass initialize] invocation shown above will actually call +[YourClass initialize]. That's just the normal inheritance mechanism at work. That will make the second time that +[YourClass initialize] has been called.
Since the work done in a +initialize method is usually the sort of thing that should only be done once, the guard if (self == [TheClassWhoseImplementationThisMethodIsPartOf class]) is necessary. Also, that work often assumes that self refers to the current class being written, so that's also a reason for the guard.
The second answer you cite notes an exception, which is the old-style mechanism for registering KVO dependent keys with the +setKeys:triggerChangeNotificationsForDependentKey: method. That method is specific to the actual class it's invoked on, not any subclasses. You should avoid it and use the more modern +keyPathsForValuesAffectingValueForKey: or +keyPathsForValuesAffecting<Key> methods. If you must use the old way, put that part outside of the guard. Also, subclasses of such a class must call through to super which is not normally done.
Update:
A +initialize method should not normally call through to super because the runtime has already initialized the superclass. If and only if the superclass is known to register dependent keys using the old mechanism, then any subclasses must call through to super.
The same worry does not exist in the case of -init because the runtime is not automatically calling the superclass init method for you before calling yours. Indeed, if your init method does not call through to super, then nothing will have initialized the superclass's "part" of the instance.
The questions you cite have good accepted answers. To summarize, +initialize is called by the runtime on every class, so for a superclass with N subclasses, it will get called N+1 times on the superclass (once directly and once for each subclass that inherits it). Same thing if a subclass overrides it and calls super.
You can defend against this by asking at the superclass level, "is this my direct initialization by the system, and not 'super' being inherited or called by my subclass?"
if (self == [ThisSuperclass self]) {}
-init is used to initialize instances of classes and isn't invoked by the runtime by default like +initialize. Instances inherit their implementations of -init, can override the inherited implementation, and can also enjoy the benefit of the inherited implementation by calling [super init];.

Objective-c using parent properties in init method

I read that using properties in init method is considered as bad practice. But should I use parent class properites ?
For example
-(id) init
{
if (self = [super init])
{
self.parentProp = someVal; // (1)
parentProp = someVal; // (2)
}
return self;
}
What is prefered (1 or 2) and why? Thanks!
After you've called super's init method, and it has returned, the superclass's part of your object is initialized and ready for use. It's normal and expected that you use its property accessors after that. For example. If you make a subclass of UIViewController, it's normal to then set your (inherited) title property, or modify your navigationItem, in your init method.
That said, you can break this behavior. If you've overridden one of your superclass's methods (including one of its accessors methods), and then you call that method in your init method, it's up to you to be sure your overridden method will behave properly before your object is fully initialized.
More subtly, maybe you're overridden a superclass method, and then you call a different superclass method that you haven't overridden. Well, what if the method you call turns around and calls the method you have overridden? You need to be aware of this possibility too.
All that said, I reiterate that it's perfectly normal to use your superclass's property accessors to customize it after you have initialized it by calling one of its init methods.
To answer your question - neither of them.
(2) is not a property access, but direct instance variable access. It depends on the class hierarchy design, but in general I would strongly discourage from using ivars in non-private interfaces - for details, see this answer to related question
In general, you should not use any of the class public methods (including properties access) in the class initializer (and in the dealloc for that matter) - if you class hierarchy doesn't prohibit subclassing explicitly. Because if you do - the subclasses overriding these methods (or properties accessors) will get them called while being in invalid state (not yet initialized or already dealloc'ed).
While I've encountered a number of problems caused by pt.2 in general it seems to be a common practice to ignore it (i.e. to use self/parent class properties in initializer). So I would say it's up to you. Either write more code for explicit setup outside of your classes initializers and feel confident that you would never encounter this problem. Or have probably more simple/short initialization and easier usage of your class but stay aware of that problem.

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.

Why subclass NSObject?

What is the purpose/use of NSObject in Objective-C? I see classes that extend NSObject like this:
#interface Fraction : NSObject
In C++ or Java, we don't use any variables like NSObject even though we have preprocessor directives and import statements in both Objective-C and Java.
Why do classes explicitly inherit from NSObject in Objective-C? What are the consequences of not declaring inheritance from NSObject?
We use NSObject to explicitly state what a given class inherits from. I'm not sure about C++, but in Java there's something similar - the Object class. The only difference is that Java doesn't require that classes explicitly descend from Object - the language assumes anything that doesn't have a specified parent class descends from Object. Objective-C is different because it allows you to define different root classes - you are allowed to make a class that doesn't inherit from NSObject.
An example of such a different root class is NSProxy.
Have a look at the GNUstep NSObject source, it shows how the methods interact with the objective-c runtime through C functions.
+ (id) allocWithZone:(NSZone*)z
{
return NSAllocateObject(self, 0, z);
}
- (void) dealloc
{
NSDeallocateObject (self);
}
+ (BOOL) isSubclassOfClass: (Class)aClass
{
return GSObjCIsKindOf(self, aClass);
}
Since object-oriented languages have the concept of an inheritance, in any inheritance hierarchy there is a root class. In Java, the default parent class (if none is provided) is java.lang.Object, whereas in Objective-C, if you don't explicitly declare a parent class, you don't get one. Essentially, your class becomes a root class itself. This is a common mistake among Objective-C newcomers, since you normally want to inherit from NSObject in such cases.
While often problematic and puzzling, this actually allows quite a bit of flexibility, since you can define your own class hierarchies that act completely differently from NSObject. (Java doesn't allow you to do this at all.) On the other hand, unless you know what you're doing, it's easy to get yourself into trouble this way. Fortunately, the compiler will provide warnings if you call a method not defined by a class with no declared parent class, such as those you would normally expect to inherit from NSObject.
As for the "use" of NSObject, check out the documentation of the NSObject class and NSObject protocol. They define common methods used for object allocation, memory management, comparison, hashing, printing descriptions, checking class membership, querying whether objects respond to a selector, etc. Basically, NSObject is "good for" providing the core functionality of Objective-C objects free of charge.
All classes don't necessarily inherit from NSObject but it is the core for many of the classes because it provides things like alloc, retain, and release.
NSObject is the root class of all classes. In my estimation, it's 3 most basic functions are to allocate and initialize memory for you (alloc & init), as well as provide a description function.
Objective-C is all about objects sending messages to other objects -- so NSObject exists to provide that basic functionality.
If this sounds strange to you, you may wish to read more about programming paradigms, particularly object-oriented programming....In a nutshell, however, Objective C is a simple extension to the C language. C gets you the ability to program computer memory, numbers, and characters, but do anything else (like use strings, or show views, for example) you need the extension part, and NSObject is the beginning of that extension.
It may be a useful exercise to pick a class (like NSString, or any for that matter), and follow it's superclasses back to NSObject, to see what functionality each class added.
Hope that helps...
NSObject
The root class of most Objective-C class hierarchies, from which
subclasses inherit a basic interface to the runtime system and the
ability to behave as Objective-C objects.
From Apple documentation - https://developer.apple.com/documentation/objectivec/nsobject.
Basically, most of OOP programming languages explicitly or implicitly specify base class or base functionality. Otherwise you cannot build system where objects communicate with each other. Properties, memory management, message sending mechanism are partly or completely provided or supported by NSObject. Apple provide parts of the Objective-C implementation - https://opensource.apple.com/source/objc4/objc4-723/runtime/NSObject.mm.auto.html, where it's possible to see what is actually inside NSObject.
Also because Objective-C is a language from C-family, so compiler and linker needs to calculate how to layout object in memory and where put and find methods, that's only possible if you know how each of the classes/instances lays in memory and where. In case of Objective-C all base classes (NSObject, NSProxy, etc) have specification of that, so it's possible to calculate their size and add on top all inherited stuff - https://clang.llvm.org/compatibility.html#objective-c.
Consequently compiler don't let to leave a class without base class. So in the end class inheritance should lead to one of the root classes. Here is the error that appears if you don't specify it (from Xcode):
Class 'ClassWithoutBaseClass' defined without specifying a base class