What is a meta-class in Objective-C?
2017-05-12 14:55
393 查看
http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
Please note: this article is part of the older "Objective-C era" on Cocoa with Love. I don't keep these articles up-to-date; please be wary of broken code
or potentially out-of-date information. Read "A new era for Cocoa with Love" for
more.
January 17, 2010 by Matt Gallagher
Tags: Objective-C, Foundation
In this post, I look at one of the stranger concepts in Objective-C — the meta-class. Every class in Objective-C has its own associated meta-class but since you rarely ever use a meta-class directly, they can remain enigmatic. I'll start by looking at how to
create a class at runtime. By examining the "class pair" that this creates, I'll explain what the meta-class is and also cover the more general topic of what it means for data to be an object or a class in Objective-C.
The following code creates a new subclass of
runtime and adds one method to it:
The method added uses the function named
its implementation, which is defined as follows:
On the surface, this is all pretty simple. Creating a class at runtime is just three easy steps:
Allocate storage for the "class pair" (using
Add methods and ivars to the class as needed (I've added one method using
Register the class so that it can be used (using
However, the immediate question is: what is a "class pair"? The function
returns one value: the class. Where is the other half of the pair?
I'm sure you've guessed that the other half of the pair is the meta-class (it's the title of this post) but to explain what that is and why you need it, I'm going to give some background on objects and classes in Objective-C.
Every object has a class. This is a fundamental object-oriented concept but in Objective-C, it is also a fundamental part of the data. Any data structure which has a pointer to a class in the right location can be treated as an object.
In Objective-C, an object's class is determined by its
The
In fact, the basic definition of an object in Objective-C looks like this:
What this says is: any structure which starts with a pointer to a
can be treated as an
The most important feature of objects in Objective-C is that you can send messages to them:
This works because when you send a message to an Objective-C object (like the
the runtime follows object's
to the object's
in this case). The
of the
a pointer to the
methods. The runtime looks through the list of
on the
matches the message selector (in the above case,
The runtime then invokes the function (
that method.
The important point is that the
messages that you can send to an object.
Now, as you probably already know, a
is also an object. This means that you can send messages to a
In this case,
the
This works because every
an object itself. This means that the
must start with an
compatible with the
above and the next field in the structure must be a pointer to the
base classes).
As I showed last week, there are a couple different ways that a
be defined, depending on the version of the runtime you are running, but yes, they all start with an
followed by a
However, in order to let us invoke a method on a
the
itself point to a
must contain the list of
on the Class.
This leads to the definition of a meta-class: the meta-class is the class for a
Simply put:
When you send a message to an object, that message is looked up in the method list on the object's class.
When you send a message to a class, that message is looked up in the method list on the class' meta-class.
The meta-class is essential because it stores the class methods for a
There must be a unique meta-class for every
every
methods.
The meta-class, like the
an object. This means that you can invoke methods on it too. Naturally, this means that it must also have a class.
All meta-classes use the base class' meta-class (the meta-class of the top
their inheritance hierarchy) as their class. This means that for all classes that descend from
classes), the meta-class has the
as its class.
Following the rule that all meta-classes use the base class' meta-class as their class, any base meta-classes will be its own class (their
points to themselves). This means that the
on the
is an instance of itself).
In the same way that the
with its
to the meta-class of the
its own
As a further quirk, the base class' meta-class sets its
the base class itself.
The result of this inheritance hierarchy is that all instances, classes and meta-classes in the hierarchy inherit from the hierarchy's base class.
For all instances, classes and meta-classes in the
this means that all
are valid. For the classes and meta-classes, all
methods are also valid.
All this is pretty confusing in text. Greg Parker has put together an excellent
diagram of instances, classes, meta-classes and their super classes and how they all fit together.
To confirm all of this, let's look at the output of the
gave at the start of this post. The purpose of this function is to follow the
and log what it finds.
To run the
instance of the dynamically created class and invoke the
on it.
Since there is no declaration of the
I invoke it using
doesn't give a warning.
The
and tell us what objects are used as the class, meta-class and class of the meta-class.
Getting the class of an object: the
follow the
is a protected member of the class (you can't directly access other object's
The
to do this because invoking the
a
it instead returns the
of the
This is the output (minus
the program runs:
Looking at the addresses reached by following the
repeatedly:
the object is address
the class is address
the meta-class is address
the meta-class's class (i.e. the
is address
the
The value of the addresses is not really important except that it shows the progress from class to meta-class to
as discussed.
The meta-class is the class for a
Every
every
This means that all
all of the same class.
The meta-class will always ensure that the
has all the instance and class methods of the base class in the hierarchy, plus all of the class methods in-between. For classes descended from
this means that all the
protocol methods are defined for all
meta-class) objects.
All meta-classes themselves use the base class' meta-class (
for
including the base level meta-class which is the only self-defining class in the runtime.
Please note: this article is part of the older "Objective-C era" on Cocoa with Love. I don't keep these articles up-to-date; please be wary of broken code
or potentially out-of-date information. Read "A new era for Cocoa with Love" for
more.
What is a meta-class in Objective-C?
January 17, 2010 by Matt GallagherTags: Objective-C, Foundation
In this post, I look at one of the stranger concepts in Objective-C — the meta-class. Every class in Objective-C has its own associated meta-class but since you rarely ever use a meta-class directly, they can remain enigmatic. I'll start by looking at how to
create a class at runtime. By examining the "class pair" that this creates, I'll explain what the meta-class is and also cover the more general topic of what it means for data to be an object or a class in Objective-C.
Creating a class at runtime
The following code creates a new subclass of NSErrorat
runtime and adds one method to it:
Class newClass = objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0); class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:"); objc_registerClassPair(newClass);
The method added uses the function named
ReportFunctionas
its implementation, which is defined as follows:
void ReportFunction(id self, SEL _cmd) { NSLog(@"This object is %p.", self); NSLog(@"Class is %@, and super is %@.", [self class], [self superclass]); Class currentClass = [self class]; for (int i = 1; i < 5; i++) { NSLog(@"Following the isa pointer %d times gives %p", i, currentClass); currentClass = object_getClass(currentClass); } NSLog(@"NSObject's class is %p", [NSObject class]); NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class])); }
On the surface, this is all pretty simple. Creating a class at runtime is just three easy steps:
Allocate storage for the "class pair" (using
objc_allocateClassPair).
Add methods and ivars to the class as needed (I've added one method using
class_addMethod).
Register the class so that it can be used (using
objc_registerClassPair).
However, the immediate question is: what is a "class pair"? The function
objc_allocateClassPaironly
returns one value: the class. Where is the other half of the pair?
I'm sure you've guessed that the other half of the pair is the meta-class (it's the title of this post) but to explain what that is and why you need it, I'm going to give some background on objects and classes in Objective-C.
What is needed for a data structure to be an object?
Every object has a class. This is a fundamental object-oriented concept but in Objective-C, it is also a fundamental part of the data. Any data structure which has a pointer to a class in the right location can be treated as an object.In Objective-C, an object's class is determined by its
isapointer.
The
isapointer points to the object's Class.
In fact, the basic definition of an object in Objective-C looks like this:
typedef struct objc_object { Class isa; } *id;
What this says is: any structure which starts with a pointer to a
Classstructure
can be treated as an
objc_object.
The most important feature of objects in Objective-C is that you can send messages to them:
[@"stringValue" writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
This works because when you send a message to an Objective-C object (like the
NSCFStringhere),
the runtime follows object's
isapointer to get
to the object's
Class(the
NSCFStringclass
in this case). The
Classthen contains a list
of the
Methods which apply to all objects of that
Classand
a pointer to the
superclassto look up inherited
methods. The runtime looks through the list of
Methods
on the
Classand superclasses to find one that
matches the message selector (in the above case,
writeToFile:atomically:encoding:erroron
NSString).
The runtime then invokes the function (
IMP) for
that method.
The important point is that the
Classdefines the
messages that you can send to an object.
What is a meta-class?
Now, as you probably already know, a Classin Objective-C
is also an object. This means that you can send messages to a
Class.
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
In this case,
defaultStringEncodingis sent to
the
NSStringclass.
This works because every
Classin Objective-C is
an object itself. This means that the
Classstructure
must start with an
isapointer so that it is binary
compatible with the
objc_objectstructure I showed
above and the next field in the structure must be a pointer to the
superclass(or
nilfor
base classes).
As I showed last week, there are a couple different ways that a
Classcan
be defined, depending on the version of the runtime you are running, but yes, they all start with an
isafield
followed by a
superclassfield.
typedef struct objc_class *Class; struct objc_class { Class isa; Class super_class; /* followed by runtime specific details... */ };
However, in order to let us invoke a method on a
Class,
the
isapointer of the
Classmust
itself point to a
Classstructure and that
Classstructure
must contain the list of
Methods that we can invoke
on the Class.
This leads to the definition of a meta-class: the meta-class is the class for a
Classobject.
Simply put:
When you send a message to an object, that message is looked up in the method list on the object's class.
When you send a message to a class, that message is looked up in the method list on the class' meta-class.
The meta-class is essential because it stores the class methods for a
Class.
There must be a unique meta-class for every
Classbecause
every
Classhas a potentially unique list of class
methods.
What is the class of the meta-class?
The meta-class, like the Classbefore it, is also
an object. This means that you can invoke methods on it too. Naturally, this means that it must also have a class.
All meta-classes use the base class' meta-class (the meta-class of the top
Classin
their inheritance hierarchy) as their class. This means that for all classes that descend from
NSObject(most
classes), the meta-class has the
NSObjectmeta-class
as its class.
Following the rule that all meta-classes use the base class' meta-class as their class, any base meta-classes will be its own class (their
isapointer
points to themselves). This means that the
isapointer
on the
NSObjectmeta-class points to itself (it
is an instance of itself).
Inheritance for classes and meta-classes
In the same way that the Classpoints to the superclass
with its
super_classpointer, the meta-class points
to the meta-class of the
Class'
super_classusing
its own
super_classpointer.
As a further quirk, the base class' meta-class sets its
super_classto
the base class itself.
The result of this inheritance hierarchy is that all instances, classes and meta-classes in the hierarchy inherit from the hierarchy's base class.
For all instances, classes and meta-classes in the
NSObjecthierarchy,
this means that all
NSObjectinstance methods
are valid. For the classes and meta-classes, all
NSObjectclass
methods are also valid.
All this is pretty confusing in text. Greg Parker has put together an excellent
diagram of instances, classes, meta-classes and their super classes and how they all fit together.
Experimental confirmation of this
To confirm all of this, let's look at the output of the ReportFunctionI
gave at the start of this post. The purpose of this function is to follow the
isapointers
and log what it finds.
To run the
ReportFunction, we need to create an
instance of the dynamically created class and invoke the
reportmethod
on it.
id instanceOfNewClass = [[newClass alloc] initWithDomain:@"someDomain" code:0 userInfo:nil]; [instanceOfNewClass performSelector:@selector(report)]; [instanceOfNewClass release];
Since there is no declaration of the
reportmethod,
I invoke it using
performSelector:so the compiler
doesn't give a warning.
The
ReportFunctionwill now traverse through the
isapointers
and tell us what objects are used as the class, meta-class and class of the meta-class.
Getting the class of an object: the
ReportFunctionuses
object_getClassto
follow the
isapointers because the
isapointer
is a protected member of the class (you can't directly access other object's
isapointers).
The
ReportFunctiondoes not use the
classmethod
to do this because invoking the
classmethod on
a
Classobject does not return the meta-class,
it instead returns the
Classagain (so
[NSString class]will return the
NSStringclass instead
of the
NSStringmeta-class).
This is the output (minus
NSLogprefixes) when
the program runs:
This object is 0x10010c810. Class is RuntimeErrorSubclass, and super is NSError. Following the isa pointer 1 times gives 0x10010c600 Following the isa pointer 2 times gives 0x10010c630 Following the isa pointer 3 times gives 0x7fff71038480 Following the isa pointer 4 times gives 0x7fff71038480 NSObject's class is 0x7fff710384a8 NSObject's meta class is 0x7fff71038480
Looking at the addresses reached by following the
isavalue
repeatedly:
the object is address
0x10010c810.
the class is address
0x10010c600.
the meta-class is address
0x10010c630.
the meta-class's class (i.e. the
NSObjectmeta-class)
is address
0x7fff71038480.
the
NSObjectmeta-class' class is itself.
The value of the addresses is not really important except that it shows the progress from class to meta-class to
NSObjectmeta-class
as discussed.
Conclusion
The meta-class is the class for a Classobject.
Every
Classhas its own unique meta-class (since
every
Classcan have its own unique list of methods).
This means that all
Classobjects are not themselves
all of the same class.
The meta-class will always ensure that the
Classobject
has all the instance and class methods of the base class in the hierarchy, plus all of the class methods in-between. For classes descended from
NSObject,
this means that all the
NSObjectinstance and
protocol methods are defined for all
Class(and
meta-class) objects.
All meta-classes themselves use the base class' meta-class (
NSObjectmeta-class
for
NSObjecthierarchy classes) as their class,
including the base level meta-class which is the only self-defining class in the runtime.
相关文章推荐
- What is a meta-class in Objective-C?
- What is a metaclass in Python?
- what-is-a-metaclass-in-python
- What is a typedef enum in Objective C?
- What is the difference between @staticmethod and @classmethod in Python?
- What is the Difference Between Type and Class in
- [Training Video - 3] [Groovy in Detail] What is a groovy class ?
- What all is inherited from parent class in C++?
- What happens when more restrictive access is given to a derived class method in C++?
- What is PostBack in ASP.NET
- Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id)等
- Objective-C中的meta-class
- 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
- Objective-C中的meta-class
- 实习小记-python中可哈希对象是个啥?what is hashable object in python?
- Objc Class And Metaclass(Objective-C类和原类)
- 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
- What is the best way to port from Objective-C to C++?
- What exactly is null in Java?[转]
- 'tools.jar' is not in IDEA classpath. Please ensure JAVA_HOME points to JDK rather than JRE.