How to create a root object in Objective-C without NSObject? - objective-c

The documentation says:
While not strictly a part of the
language, the isa pointer is required
for an object to work with the
Objective-C runtime system. An object
needs to be “equivalent” to a struct
objc_object (defined in objc/objc.h)
in whatever fields the structure
defines. However, you rarely, if ever,
need to create your own root object,
and objects that inherit from NSObject
or NSProxy automatically have the isa
variable.
While that sounds nice, I wonder how an root object would be created in Objective-C anyways?
This is for learning purposes. I just want to know this. I'd really like to see it.

It's actually a "trap" some people migrating from C# or Java style languages fall into. You simply don't specify a superclass when declaring your class i.e.
#interface MyNewRoot {
Class isa;
}
#end
vs
#interface MyObject : NSObject {
}
#end
In Java or C# these would be equivalent (in the first case the compiler would assume System.Object or java.lang.Object was the superclass), but in Objective-C no such default will be assumed, and hence a new root is created.
However you're now responsible for a number of features for your class that you typically take for granted (even simple things like memory management for allocating or destorying new instances etc). This is what the comment you quoted hints at when it talks about struct objc_object and the isa instance variable etc.

Related

Why is a pointer on an ivar bad in Objective-C?

I am reading "Effective Objective-C 2.0: 52 Specific Ways to Improve Your iOS and OS X Programs". In "Item 6", the author says that using a pointer on a public ivar is a bad idea, because compiled code will have hardcoded pointer offset, and when new ivar will be added to class, then previously used pointers to some ivars can now point on other variable.
#interface Foo
{
#public
NSString * string;
NSArray * arr;
}
#end
#implementation
...
#end
int main()
{
#autoreleasepool
{
Foo *f=[Foo new];
f->string; //Is it bad idea?
}
return 0;
}
But, aren't ivars and properties dynamic (offset is not known at compile-time)? As Cocoa With Love says:
"All ivars are dynamic in the modern runtime: Since this procedure is followed for all ivars, that means that all ivars in the modern Objective-C runtime are dynamic in that their absolute offsets are never known at compile-time."
If that's true, then why is using a pointer on an ivar bad? Please provide as much low-level detail as possible.
If that's true, then why is using a pointer on an ivar bad? Please
provide as much low-level detail as possible.
Because it breaks encapsulation.
What if class Foo has some custom logic that should be fired when string changes? Or it has to do a calculation? Or Foo wants to make the storage of string unique-ified? Or something else wants to observe changes to said property? Or Foo wants to change the storage semantics later? Or someone wants to subclass Foo and change the behavior there?
Not a problem: "All instance variables in 64-bit Objective-C are non-fragile. That is, existing compiled code that uses a class's ivars will not break when the class or a superclass changes its own ivar layout. In particular, framework classes may add new ivars without breaking subclasses compiled against a previous version of the framework." (https://developer.apple.com/LIBRARY/mac/releasenotes/Cocoa/RN-ObjectiveC/index.html)
This also holds for the 32 bit modern runtime, of course.
Apart from the implementation technicalities, it's an exceptionally bad design though, as bbum notes.

What is a class object in Objective-C 2.0?

In the official documentation for Objective C 2.0 titled The Objective-C 2.0 Programming Language from Apple, released in 2009, there is a paragraph about Class Objects on page 28.
I don't understand what Class Objects are, and how to define them aside from the rest of the language and what properties they have. In the same document it's explained that everything in Objective-C 2.0 is an object, this object is basically a pointer to a struct that contains an isa field and the pointer itself is of type id.
From this I'm deducing that:
inheritance in Obj-C 2.0 basically consists in chaining those struct through the id and isa field
objects that are superclass construct the isa field in a way that it points to a nil object.
id is a valid datatype for pretty much everything in Objective C 2.0
when defining a class, everything that defines the class itself ( methods and variables ) is packed starting from after/below the isa pointer
Assuming that I got how Objective C 2.0 works, what is a class object and how is it different from the way instances are created? What kind of properties does a class object offer that an instance doesn't have ? Can you make a parallel with C or C++?
OK, so you define a class. We'll call him Charlie:
#interface Charlie : NSObject
#end
There's our little class! Since — like every other class in Obective-C — Charlie is an object, you can send it messages like [Charlie alloc] to have Charlie allocate an instance for you. This is what we mean by a class object: It's the object that represents the class you defined.
What is an object in Objective-C? Classes are defined based on this struct:
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
And a class is represented by a struct like this:
struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
// A bunch of other members …
}
As you can see, the both start with an isa referring to a class. So a class is just an extension of normal objects.
When Charlie creates an instance, that instance's isa will point to Charlie. But what does Charlie's isa point to? Well, it points to a metaclass. A metaclass is a strange thing — it's a special kind of class that exists just to act as a class's class. You never interact with it directly; it just does its classly duties† when you interact with its sole instance, Charlie.
So that's what we mean when we talk about a class object — it's just the object that represents the class you defined in code.
† You might be wondering what a class's duties are. Well, the obvious biggie is that it's how you create your objects. But besides that, instances in Objective-C do not hold their own methods. Instead, method resolution is done based on an object's isa, so the class's most important function, besides creating instances for you, is determining what methods your object has.
what is a class object and how it's different from the way instances
are created ? What kind of properties a class object offers that an
instance doesn't have ? Can you make a parallel with C or C++ ?
Let's try to compare with C and C++. First there is no comparison to C, because C is not object oriented, so the concept of object or class does not exist. In C++ you have classes (or objects) which you declare in your .h file, there you write the definition of the class (the name, the instance variables, and methods or functions), and then in your .cpp file you implement the methods declared in the definition.
Also in C++ you can have static variables and methods, which, as you probably know, don't belong to a specific instance of the class, we could say that they affect all instances.
In objective C, a class property or a class method is analogous to the static variables and static funcions in C++.
A class object is the way objective C encapsulates the definition of a class and makes it available at runtime. You don't necessarily instantiate class objects explicitly.
Consider this class
#interface MyObject : NSObject
{
int i;
}
- (void)myFunction;
+ (void)classFunction;
#end
You can instantiate such an object using:
MyObject *obj = [[MyObject alloc] init];
Here you're using the alloc method of the MyObject class object. Something important to understand is that you don't instantiate class Objects, the compiler creates just one object, a class object, to represent the class.
Object is a structure, that has isa field pointing to its Class. This isa allows the structure to receive Objective-C messages, which makes it an Object. Class pointed by isa is used to lookup implementations for these messages.
(Interestingly, also blocks are objects and GCD structures are too. They both can receive messages, like -copy for blocks or -description for dispatch_queue.)
Class is a structure used to look-up methods of its instances. It has a list of method implementations for their instances (-methods). Classes have an isa field, so they qualify as Objects, thus can also receive messages. isa of Class points to a Metaclass, so a Class is instance of a Metaclass. Its single instance – a singleton.
Metaclass is where I'm getting lost, but it's definitely an Object, because it has isa. Metaclass has a list of method implementations (+methods) of its single instance – the Class.
When you write this code:
#interface MYObject : NSObject
+ (void)classMethod; // Stored in Metaclass
- (void)instanceMethod; // Stored in Class
#end
You are creating a pair: Class and Metaclass.
Oh, and what is a class of Metaclass? A Root Metaclass!
And what is a class of the Root Metaclass? The Root Metaclass itself!
But then where isa of Metaclasses points to? To our old friend NSObject. Too meta, right?

Why are Objective-C instance variables declared in an interface?

I'm just getting into Objective-C (Java is my primary OO language).
Defining an object's instance variables in the interface instead of the class seems strange. I'm used to an interface being a public API definition with nothing besides method signatures (not counting constants here).
Is there some reason that state is defined in an interface (even if it is private) and behaviour is defined in a class. It just seems odd that since objects are state+behavior that the definition would be split into two separate places.
Is it a design benefit is some way? A pain in the rear issue that you are just forced to deal with in Objective-C? A non-issue, just different? Any background on why it's done this way?
Or can you put object state in a class and I just haven't hit that part in my book yet?
UPDATE
The answer below was written before the language feature of declaring instance variables in the implementation was implemented. The premise of the question is now no longer valid. As FireLizzard says, nothing needs to go in the #interface that you don't want to be public.
It's a hangover from the fact that Objective-C originated as a fairly thin layer built on top of C. The C way is to define the interface to a module (do not confuse with a Java interface) in a header file and literally include it in each compilation unit. It's akin to automatically copy-pasting the declarations to the top of every compiled file. If that seems primitive, it is because it is, but C is a 40 year old language.
You have to define instance variables - even private ones - in the interface because Objective-C objects are implemented as C structs which are themselves just blocks of memory and named offsets within that block. The struct that represents an object of each class has to include space for the superclass instance variables so subclasses need to know at least the size of the C struct representing the superclass and also the public and protected instance variable offset. That, unfortunately, means that all the instance variables even private ones have to be exposed as part of the external interface.* C++ the other OO version of C suffers from the same problem for the same reasons.
It's a bit of a pain having to write down all the method signatures twice, but you get used to it.
*With the 64 bit runtime, you no longer need to declare the ivars for synthesized accessors in the #interface but since all methods are public, it still means exposing internal state to the outside World, althoug it does alleviate the fragile base class problem.
In Objective C interface does not refer to the instance at all
Brad Cox who designed Objective C decided that the equivalent of C declarations and definitions should be made explicit so each class has a #interface section telling what it looks like externally and an #implementation saying how it is implemented.
Java came along later and changed the object model so that there is only one definition of an object which pulled the #interface and #implementation together. The compiler (and runtime introspection) in effect construct the interface from the code.
The equivalent of an interface in Java is a Protocol in Objective C.
You just get used to it.

Objective-C Basic Class question

So I'm a bit rusty getting back into programming and I can't seem to find a good reference for understanding the structure for what I am trying to achieve. So, without further ado I am looking at creating and Class object such as.
#import Assets.h
#interface MainRecord: NSObject {
Assets* assets;
...
}
...
#end
Having a class object within a class, do i need to initialize when the object is created in main? I want to make sure each instance created for MainRecord will always be associated with it's Assets.(in the future these will be written to a file) All of which is mainly for readability and ease of adding objects to this class.
I recommend reading (at least parts of) The Objective-C 2.0 Programming Language, a guide published by Apple. The section called "Defining a Class" will answer the bulk of your questions.
Basically, you don't initialize instance variables in main() — the class defines methods that handle its own variables. (This is common practice for object-oriented programming languages.) In Objective-C you initialize instance variables in an -(id)init method and release them in -(void)dealloc method to avoid leaking memory. For example, see all the -initWith... methods in NSString.

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