NSLog(@"%@ isMemberOfClass %@ result %@", NSStringFromClass(ccls),NSStringFromClass(ccls),@([ccls isMemberOfClass:ccls])); NSLog(@"%@ isMemberOfClass %@ result %@", NSStringFromClass(icls),NSStringFromClass(icls),@([icls isMemberOfClass:icls])); NSLog(@"%@ isMemberOfClass %@ result %@", NSStringFromClass(icls),NSStringFromClass(ccls),@([icls isMemberOfClass:ccls]));
这里我们判断输出结果应该为: 1 1 1
结果分析
那么我们带着上面的猜测,确认打印输出:
1 2 3 4 5 6
2021-01-0119:26:08.475701+0800 MetaClassDemo[5964:166878] NSObject isKindOfClass NSObject result 1 2021-01-0119:26:08.475858+0800 MetaClassDemo[5964:166878] Person isKindOfClass Person result 0 2021-01-0119:26:08.475963+0800 MetaClassDemo[5964:166878] Person isKindOfClass NSObject result 1 2021-01-0119:26:08.476068+0800 MetaClassDemo[5964:166878] NSObject isMemberOfClass NSObject result 0 2021-01-0119:26:08.476188+0800 MetaClassDemo[5964:166878] Person isMemberOfClass Person result 0 2021-01-0119:26:08.476315+0800 MetaClassDemo[5964:166878] Person isMemberOfClass NSObject result 0
Class ccls = [NSObjectclass]; Class icls = [Person class]; Class scls = [Female class]; NSLog(@"%@ isKindOfClass %@ result %@", NSStringFromClass(icls),NSStringFromClass(ccls),@([icls isKindOfClass:ccls])); NSLog(@"%@ isKindOfClass %@ result %@", NSStringFromClass(scls),NSStringFromClass(icls),@([scls isKindOfClass:icls]));
结果:1,0。 这也验证了我们上面的结论
isMemberOfClass
[A isMemberOfClass: B]
B 类是否为A类元类 对于类方法的调用中这个条件是永远都不成立的。无论A与B之间是否存在继承或者被继承关系。
对象方法
实际我们平时开发中最常用的是
1 2 3 4 5 6 7 8
- (void)instanceTest { Female *f = [Female new];
NSLog(@"%@ isKindOfClass %@ result %@", NSStringFromClass([f class]),NSStringFromClass([Person class]),@([f isKindOfClass:[Person class]])); NSLog(@"%@ isMemberOfClass %@ result %@", NSStringFromClass([f class]),NSStringFromClass([Person class]),@([f isMemberOfClass:[Person class]])); NSLog(@"%@ isMemberOfClass %@ result %@", NSStringFromClass([f class]),NSStringFromClass([Female class]),@([f isMemberOfClass:[Female class]]));
}
打印结果:
1 2 3
2021-01-0123:27:53.040093+0800 MetaClassDemo[8537:312528] Female isKindOfClass Person result 1 2021-01-0123:27:53.040223+0800 MetaClassDemo[8537:312528] Female isMemberOfClass Person result 0 2021-01-0123:27:53.040337+0800 MetaClassDemo[8537:312528] Female isMemberOfClass Female result 1
struct objc_class : objc_object { // Class ISA; Class superclass; cache_t cache; // formerly cache pointer and vtable class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const { return bits.data(); } // NOT identical to this->ISA when this is a metaclass Class getMeta() { if (isMetaClass()) return (Class)this; elsereturnthis->ISA(); } }
Class objc_allocateClassPair(Class superclass, constchar *name, size_t extraBytes) { Class cls, meta;
rwlock_writer_t lock(runtimeLock);
// Fail if the class name is in use. // Fail if the superclass isn't kosher. if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) { returnnil; }
// Allocate new classes. cls = alloc_class_for_subclass(superclass, extraBytes); meta = alloc_class_for_subclass(superclass, extraBytes);
// fixme mangle the name if it looks swift-y? objc_initializeClassPair_internal(superclass, name, cls, meta);
return cls; }
从上面的代码中我们可以很明显的看出:
1 2
cls = alloc_class_for_subclass(superclass, extraBytes); meta = alloc_class_for_subclass(superclass, extraBytes);
Metaclasses in Objective-C are almost the same as those in Smalltalk-80—not surprising since Objective-C borrows a lot from Smalltalk. Like Smalltalk, in Objective-C, the instance variables and methods are defined by an object's class. A class is an object, hence it is an instance of a metaclass.(OC中的Metaclasses 基本上和Smalltalk-80相同,鉴于OC从Smalltalk中借鉴了很多因此这并不令人干到奇怪。类似Smalltalk 在OC中实例的变量和方法被定义在对象的类中,class也是一个对象,于是class是mataclass的一个实例。)
Like Smalltalk, in Objective-C, class methods are simply methods called on the class object, hence a class's class methods must be defined as instance methods in its metaclass. Because different classes can have different sets of class methods, each class must have its own separate metaclass. Classes and metaclasses are always created as a pair: the runtime has functions objc_allocateClassPair() and objc_registerClassPair() to create and register class-metaclass pairs, respectively.(类似Smalltalk,在OC中类方法通过类对象调用,于是一个类的类方法必须在metaclass中以实例方法的形式定义。因为不同的类可以后不同的类方法集合,每一个类必须有自己独立的metaClass。Class和class-metaClass一起被创建和注册)
There are no names for the metaclasses; however, a pointer to any class object can be referred to with the generic type Class (similar to the type id being used for a pointer to any object). (metaClass没有名字,然而,指向任何类对象的指针可以用泛型类型引用)(类似id可以指向所有的对象)
Because class methods are inherited through inheritance, like Smalltalk, metaclasses must follow an inheritance scheme paralleling that of classes (e.g. if class A's parent class is class B, then A's metaclass's parent class is B's metaclass), except that of the root class.(因为,类方法通过继承获取,类似Smalltalk,元类必须遵循与类类似的继承方案
Unlike Smalltalk, the metaclass of the root class inherits from the root class (usually NSObject using the Cocoa framework) itself. This ensures that all class objects are ultimately instances of the root class, so that you can use the instance methods of the root class, usually useful utility methods for objects, on class objects themselves.(与Smalltalk不同,根类的metaclass继承自根类本身,这就确保了所有的类对象都是根类的对象。以便您可以使用根类的实例方法,通常是对象的有用实用工具方法,以及类对象本身。)
Since metaclass objects do not behave differently (you cannot add class methods for a metaclass, so metaclass objects all have the same methods), they are all instances of the same class—the metaclass of the root class (unlike Smalltalk). Thus, the metaclass of the root class is an instance of itself. The reason for this is that all metaclasses inherit from root class; hence, they must inherit the class methods of the root class. (由于元类对象行为不同(你不能为元类添加类方法,所以元类对象都有相同的方法),它们都是同一类的实例 - 根类的元类(与Smalltalk不同)因此,根类的元类是它自己的一个实例。原因是所有元类都继承自根类;因此,他们必须继承根类的类方法。)