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.

isKindOfClassAnalysis 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

  1. 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
  1. To understandisTaggedPointer()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 currentobjcFor instance objects, then(isa.bits & ISA_MASK)The returned result must correspond to the current instance objectclass.
  • The currentobjcIf the class object, then(isa.bits & ISA_MASK)The returned result must correspond to the current class objectThe metaclass.
  1. Analysis of the
  • IsKindOfClass class methodThe underlying function is actually oneforLoop, looking up through the inheritance chain
  • object_getClass((id)self), the currentobjcIs 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 getNSObjectMetaclass, matchNSObjectClass, fail.
  • Enter cyclic basisNSObjectMetaclass, findsuperclassTo obtainNSObjectClass, matchingNSObjectClass, success.

Analysis of the

BOOL b3 = [[XDPerson class] isKindOfClass:[XDPerson class]];
Copy the code
  • The first step of the search is to getXDPersonMetaclass, matchXDPersonClass, fail.
  • Enter cyclic basisXDPersonMetaclass, findsuperclassTo obtainNSObjectMetaclass, matchXDPersonClass, fail.
  • Enter cyclic basisNSObjectMetaclass, findsuperclassTo obtainNSObjectClass, matchingXDPersonClass, fail.
  • Enter cyclic basisNSObjectClass, 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

  1. 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.

  1. Analysis of the
  • IsKindOfClass object methodThe 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.eNSObjectClass, matchingNSObjectAnd 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.eXDPersonClass, matchingXDPersonAnd success.

isMemberOfClassAnalysis 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

  1. 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.

  1. 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

  1. The underlying source
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
Copy the code
  1. 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. isKindOfClassconclusion

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. isMemberOfClassconclusion

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