preface
- IOS low-level exploration — Alloc, init, new exploration
- IOS Low-level Exploration – Memory byte alignment analysis
- IOS Low-level Exploration – The nature of objects
- IOS Low-level Exploration – Isa initialization & Pointing Analysis
- IOS Low-level exploration – Class structure analysis
- IOS Low-level Exploration — Cache_T Analysis
- IOS Low-level Exploration – method lookup flow
- IOS Low-level Exploration – Method forwarding flow
Purpose to explore
The exploration of isKindOfClass and isMemberOfClass in this paper is to deepen the understanding of ISA pointing analysis.
The code analysis
Code 1.
BOOL b1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL b2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL b3 = [[XDPerson class] isKindOfClass:[XDPerson class]];
BOOL b4 = [[XDPerson class] isMemberOfClass:[XDPerson class]];
BOOL b5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL b6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL b7 = [[XDPerson alloc] isKindOfClass:[XDPerson class]];
BOOL b8 = [[XDPerson alloc] isMemberOfClass:[XDPerson class]];
NSLog(@"b1 - %d",b1);
NSLog(@"b2 - %d",b2);
NSLog(@"b3 - %d",b3);
NSLog(@"b4 - %d",b4);
NSLog(@"b5 - %d",b5);
NSLog(@"b6 - %d",b6);
NSLog(@"b7 - %d",b7);
NSLog(@"b8 - %d",b8);
Copy the code
See the above code, I do not know whether readers can be the first time to answer all the correct, I did not have a thorough understanding of the ISA before pointing, all rely on the mask. For those of you who are not familiar with ISA, check out this article on iOS Basics: Isa Initialization & Pointing Analysis.
2. Output the result
I don’t know if the reader’s analysis is correct. If all of them are correct and you know the reason, congratulations, you don’t need to see my analysis below. If you don’t know why, then I think you need to read my analysis below.
isKindOfClass
Analysis of the
1. Low-level analysis of class methods
1.1 Class method examples
BOOL b1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL b3 = [[XDPerson class] isKindOfClass:[XDPerson class]];
Copy the code
1.2 Basic principles of class methods
- The underlying source
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
Copy the code
Object_getClass ((id)self); object_getClass((id)self);
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
inline Class
objc_object::getIsa()
{
if(! isTaggedPointer())return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
inline Class
objc_object::ISA() { assert(! isTaggedPointer());#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
Copy the code
- To understand
isTaggedPointer()
function
inline bool
objc_object::isTaggedPointer()
{
return _objc_isTaggedPointer(this);
}
Copy the code
define _OBJC_TAG_MASK 1UL
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr)
{
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
Copy the code
` `
* * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer * * taggedPointer
SUPPORT_INDEXED_ISA
#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && ! __LP64__)
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
Copy the code
Macros are defined as 0 on iOS mobile platforms.
Through the analysis in the second step, the code goes to ISA() -> (Class)(ISa.bits & ISA_MASK).
We learned about this in the iOS Low-level exploration – Isa initialization & Pointing Analysis article (if not clear, please go to this article)
- The current
objc
For instance objects, then(isa.bits & ISA_MASK)
The returned result must correspond to the current instance objectclass.- The current
objc
If the class object, then(isa.bits & ISA_MASK)
The returned result must correspond to the current class objectThe metaclass.
- Analysis of the
IsKindOfClass class method
The underlying function is actually onefor
Loop, looking up through the inheritance chainobject_getClass((id)self)
, the currentobjc
Is a class object, then the obtained class is the metaclass of the current class.
Analysis of the
BOOL b1 = [[NSObject class] isKindOfClass:[NSObject class]];;
Copy the code
- The first step of the search is to get
NSObject
Metaclass, matchNSObject
Class, fail.- Enter cyclic basis
NSObject
Metaclass, findsuperclass
To obtainNSObject
Class, matchingNSObject
Class, success.
Analysis of the
BOOL b3 = [[XDPerson class] isKindOfClass:[XDPerson class]];
Copy the code
- The first step of the search is to get
XDPerson
Metaclass, matchXDPerson
Class, fail.- Enter cyclic basis
XDPerson
Metaclass, findsuperclass
To obtainNSObject
Metaclass, matchXDPerson
Class, fail.- Enter cyclic basis
NSObject
Metaclass, findsuperclass
To obtainNSObject
Class, matchingXDPerson
Class, fail.- Enter cyclic basis
NSObject
Class, look forsuperclass
, gets nil, breaks out of the loop, fails to match.
2. Low-level analysis of object methods
2.1 Object method examples
BOOL b5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL b7 = [[XDPerson alloc] isKindOfClass:[XDPerson class]];
Copy the code
2.2 Underlying principles of object methods
- The underlying source
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
Copy the code
[self class] Specifies the current class of the object.
- Analysis of the
IsKindOfClass object method
The underlying function is essentially a for loop that looks up through the inheritance chain.[self class]
Gets the current class directly.
Analysis of the
BOOL b5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
Copy the code
- The first step is to get the class of the object, i.e
NSObject
Class, matchingNSObject
And success.
Analysis of the
BOOL b7 = [[XDPerson alloc] isKindOfClass:[XDPerson class]];
Copy the code
- The first step is to get the class of the object, i.e
XDPerson
Class, matchingXDPerson
And success.
isMemberOfClass
Analysis of the
1. Low-level analysis of class methods
1.1 Class method examples
BOOL b2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL b4 = [[XDPerson class] isMemberOfClass:[XDPerson class]];
Copy the code
1.2 Basic principles of class methods
- The underlying source
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
Copy the code
Combined with the isKindOfClass method, the distinction is to only find the current, do not go through the inheritance chain.
- Analysis of the
Object_getClass ((id)self) gets the metaclass.
Analysis of the
BOOL b2 = [[NSObject class] isMemberOfClass:[NSObject class]];
Copy the code
Got NSObject metaclass, match NSObject, failed.
Analysis of the
BOOL b4 = [[XDPerson class] isMemberOfClass:[XDPerson class]];
Copy the code
Get XDPerson metaclass, match XDPerson class, failed.
2. Low-level analysis of object methods
2.1 Object method examples
BOOL b6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL b8 = [[XDPerson alloc] isMemberOfClass:[XDPerson class]];
Copy the code
2.2 Underlying principles of object methods
- The underlying source
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
Copy the code
- Analysis of the
Gets the class of the object directly.
Analysis of the
BOOL b6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
Copy the code
Got NSObject, matched NSObject, success.
Analysis of the
BOOL b8 = [[XDPerson alloc] isMemberOfClass:[XDPerson class]];
Copy the code
The XDPerson class is obtained and matches the XDPerson class. Success.
conclusion
1. isKindOfClass
conclusion
IsKindOfClass queries along the inheritance chain.
+
Class method that gets the metaclass and looks it up the inheritance chain of the metaclass.-
Object method that retrieves the class and looks up the class’s inheritance chain.
2. isMemberOfClass
conclusion
IsMemberOfClass finds only the current.
+
Class method to get the metaclass.-
Object method that gets the class.
Finally, attached is the isa pointing and inheritance chain diagram, all explanations can be found in this diagram.
The road of learning, forge ahead
The shortcomings can be pointed out in the comments section