General situation of

As the core class of YYModel, YYClassInfo is an essential part of YYModel to parse Json to model. In fact, it mainly uses runTime to obtain the internal information of class, thus providing a convenient tool for CONVERTING Json to Model. Learning THE YYClassInfo class will help you understand how YYModel works and strengthen the basic skills of the runTime. Let’s get started.

YYClassInfo class preview

YYClassInfo. H files and. M files can be divided into 5 parts.

  1. YYEncodingType
  2. YYClassIvarInfo
  3. YYClassMethodInfo
  4. YYClassPropertyInfo
  5. Each part of YYClassInfo is responsible for a specific responsibility. The following parts are analyzed one by one according to the sequence of the five parts.

YYEncodingType module

//YYClassInfo.h
/**
 Type encoding's type.
 */
typedef NS_OPTIONS(NSUInteger, YYEncodingType) {
    YYEncodingTypeMask       = 0xFF, ///< mask of type value
    YYEncodingTypeUnknown    = 0, ///< unknown
    YYEncodingTypeVoid       = 1, ///< void
    YYEncodingTypeBool       = 2, ///< bool
    YYEncodingTypeInt8       = 3, ///< char / BOOL
    YYEncodingTypeUInt8      = 4, ///< unsigned char
    YYEncodingTypeInt16      = 5, ///< short
    YYEncodingTypeUInt16     = 6, ///< unsigned short
    YYEncodingTypeInt32      = 7, ///< int
    YYEncodingTypeUInt32     = 8, ///< unsigned int
    YYEncodingTypeInt64      = 9, ///< long long
    YYEncodingTypeUInt64     = 10, ///< unsigned long long
    YYEncodingTypeFloat      = 11, ///< float
    YYEncodingTypeDouble     = 12, ///< double
    YYEncodingTypeLongDouble = 13, ///< long double
    YYEncodingTypeObject     = 14, ///< id
    YYEncodingTypeClass      = 15, ///< Class
    YYEncodingTypeSEL        = 16, ///< SEL
    YYEncodingTypeBlock      = 17, ///< block
    YYEncodingTypePointer    = 18, ///< void*
    YYEncodingTypeStruct     = 19, ///< struct
    YYEncodingTypeUnion      = 20, ///< union
    YYEncodingTypeCString    = 21, ///< char*
    YYEncodingTypeCArray     = 22, ///< char[10] (for example)
    
    YYEncodingTypeQualifierMask   = 0xFF00,   ///< mask of qualifier
    YYEncodingTypeQualifierConst  = 1 << 8,  ///< const
    YYEncodingTypeQualifierIn     = 1 << 9,  ///< in
    YYEncodingTypeQualifierInout  = 1 << 10, ///< inout
    YYEncodingTypeQualifierOut    = 1 << 11, ///< out
    YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy
    YYEncodingTypeQualifierByref  = 1 << 13, ///< byref
    YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway
    
    YYEncodingTypePropertyMask         = 0xFF0000, ///< mask of property
    YYEncodingTypePropertyReadonly     = 1 << 16, ///< readonly
    YYEncodingTypePropertyCopy         = 1 << 17, ///< copy
    YYEncodingTypePropertyRetain       = 1 << 18, ///< retain
    YYEncodingTypePropertyNonatomic    = 1 << 19, ///< nonatomic
    YYEncodingTypePropertyWeak         = 1 << 20, ///< weak
    YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter=
    YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter=
    YYEncodingTypePropertyDynamic      = 1 << 23, ///< @dynamic
};

YYEncodingType YYEncodingGetType(const char *typeEncoding);
Copy the code

Yyclassinfo. h file about YYEncodingType module source code. We first define a shifted enumeration type whose enumeration values can be bitwise or operatively combined of multiple types. YYEncodingTypexxx records the type of the attribute, YYEncodingTypeQualifier records the key word of the attribute, and YYEncodingTypeProperty records the modification of the attribute. One YYEncodingTypeMask YYEncodingTypeQualifierMask YYEncodingTypePropertyMask, can realize value operation, For example, YYEncodingTypeMask and the & operation of the enumeration value can obtain the lower 8 bits value, which is the value of the enumeration. That is multiple enumerated values take | operation can realize the combination of multiple enumerated values, such as a variable can store up to three enumeration values (YYEncodingType YYEncodingTypeQualifier, YYEncodingTypeProperty) combination. This variable and YYEncodingTypeMask am& operation can obtain the value of the lower 8 bits, that is, the value of YYEncodingType. By this method, the three state enumerations are worth combining and obtaining the specific enumeration value. YYEncodingType YYEncodingGetType(const char *typeEncoding); This method is a way to get enumeration values to see the implementation file

YYEncodingType YYEncodingGetType(const char *typeEncoding) {
    char *type = (char *)typeEncoding;
    //typeReturns if it is nullif (!type) return YYEncodingTypeUnknown;
    size_t len = strlen(type);
    //typeIf the length is 0, returnif (len == 0) returnYYEncodingTypeUnknown; YYEncodingType qualifier = 0; YYEncodingType qualifier = 0; // End of loop control variable bool prefix =true; The following code is used to obtain the value of YYEncodingTypeQualifier type stored in the qualifier variablewhile (prefix) {
        switch (*type) {
            case 'r': {
                qualifier |= YYEncodingTypeQualifierConst;
                type+ +; }break;
            case 'n': {
                qualifier |= YYEncodingTypeQualifierIn;
                type+ +; }break;
            case 'N': {
                qualifier |= YYEncodingTypeQualifierInout;
                type+ +; }break;
            case 'o': {
                qualifier |= YYEncodingTypeQualifierOut;
                type+ +; }break;
            case 'O': {
                qualifier |= YYEncodingTypeQualifierBycopy;
                type+ +; }break;
            case 'R': {
                qualifier |= YYEncodingTypeQualifierByref;
                type+ +; }break;
            case 'V': {
                qualifier |= YYEncodingTypeQualifierOneway;
                type+ +; }break;
            default: { prefix = false; } break; }} /*** 2. Get YYEncodingType ***/ strlen(type);
    //typeIf the length is 0, the unknown type is returnedif (len == 0) returnYYEncodingTypeUnknown | qualifier; The following code is used to obtain the enumeration value of type YYEncodingType stored in the qualifier variable switch (*)type) {
        case 'v': return YYEncodingTypeVoid | qualifier;
        case 'B': return YYEncodingTypeBool | qualifier;
        case 'c': return YYEncodingTypeInt8 | qualifier;
        case 'C': return YYEncodingTypeUInt8 | qualifier;
        case 's': return YYEncodingTypeInt16 | qualifier;
        case 'S': return YYEncodingTypeUInt16 | qualifier;
        case 'i': return YYEncodingTypeInt32 | qualifier;
        case 'I': return YYEncodingTypeUInt32 | qualifier;
        case 'l': return YYEncodingTypeInt32 | qualifier;
        case 'L': return YYEncodingTypeUInt32 | qualifier;
        case 'q': return YYEncodingTypeInt64 | qualifier;
        case 'Q': return YYEncodingTypeUInt64 | qualifier;
        case 'f': return YYEncodingTypeFloat | qualifier;
        case 'd': return YYEncodingTypeDouble | qualifier;
        case 'D': return YYEncodingTypeLongDouble | qualifier;
        case The '#': return YYEncodingTypeClass | qualifier;
        case ':': return YYEncodingTypeSEL | qualifier;
        case The '*': return YYEncodingTypeCString | qualifier;
        case A '^': return YYEncodingTypePointer | qualifier;
        case '[': return YYEncodingTypeCArray | qualifier;
        case '(': return YYEncodingTypeUnion | qualifier;
        case '{': return YYEncodingTypeStruct | qualifier;
        case The '@': {
            if (len == 2 && *(type+ 1) = ='? ')
                return YYEncodingTypeBlock | qualifier;
            else
                return YYEncodingTypeObject | qualifier;
        }
        default: returnYYEncodingTypeUnknown | qualifier; }}Copy the code

The above code has been commented. This method is used to get the combination of YYEncodingTypeQualifier and YYEncodingType enumeration values. (the next use YYEncodingTypeMask, YYEncodingTypeQualifierMask value) of the specific

YYClassIvarInfo module

@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar;              ///< ivar opaque struct
@property (nonatomic, strong, readonly) NSString *name;         ///< Ivar's name @property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding @property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type

/**
 Creates and returns an ivar info object.
 
 @param ivar ivar opaque struct
 @return A new object, or nil if an error occurs.
 */
- (instancetype)initWithIvar:(Ivar)ivar;
@end
Copy the code

The. H file mainly uses several attributes to store several specific values of member variables. Use – (instancetype)initWithIvar:(Ivar) Ivar method to achieve several attributes of the assignment operation, so we get the specific information of the member variable. Let’s look at the implementation.

- (instancetype)initWithIvar:(Ivar) Ivar {// if Ivar is empty, nil is returnedif(! ivar)returnnil; self = [super init]; // save ivar _ivar = ivar; Const char *name = ivar_getName(ivar);if(name) { _name = [NSString stringWithUTF8String:name]; } // Save ivar offset _offset = ivar_getOffset(ivar); / / savetypeEncoding andtype
    const char *typeEncoding = ivar_getTypeEncoding(ivar);
    if (typeEncoding) {
        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
        _type = YYEncodingGetType(typeEncoding);
    }
    return self;
}
Copy the code

Parsing: the code above is commented with typeEncoding, which is a typeEncoding defined by apple that records the type of the property. In fact, this code can record all types, including method return value types, input parameters, and so on.

YYClassMethodInfo module

@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method;                  ///< method opaque struct
@property (nonatomic, strong, readonly) NSString *name;                 ///< method name
@property (nonatomic, assign, readonly) SEL sel;                        ///< method's selector @property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
@property (nonatomic, strong, readonly) NSString *typeEncoding;         ///< method's parameter and return types @property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type /** Creates and returns a method info object. @param method method opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithMethod:(Method)method; @endCopy the code

– (instanceType)initWithMethod:(Method) Method Method to achieve specific assignment, so that the specific information of this attribute is recorded. Let’s look at the implementation.

@implementation YYClassMethodInfo - (instancetype)initWithMethod:(Method) Method {// Method returns nil if Method is emptyif(! method)returnnil; self = [super init]; // save method _method = method; // save sel _sel = method_getName(method); _imp = method_getImplementation(method); // Save the imp (imp is actually a method implementation function, which registers the address of the method implementation). // save name const char *name = sel_getName(_sel);if(name) { _name = [NSString stringWithUTF8String:name]; } / / savetypeEncoding
    const char *typeEncoding = method_getTypeEncoding(method);
    if (typeEncoding) {
        _typeEncoding = [NSString stringWithUTF8String:typeEncoding]; } / / savereturnType
    char *returnType = method_copyReturnType(method);
    if (returnType) {
        _returnTypeEncoding = [NSString stringWithUTF8String:returnType];
        free(returnType); } // Save the argument type unsigned int argumentCount = method_getNumberOfArguments(method);if (argumentCount > 0) {
        NSMutableArray *argumentTypes = [NSMutableArray new];
        for (unsigned int i = 0; i < argumentCount; i++) {
            char *argumentType = method_copyArgumentType(method, i);
            NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
            [argumentTypes addObject:type ? type : @""];
            if (argumentType) free(argumentType);
        }
        _argumentTypeEncodings = argumentTypes;
    }
    return self;
}

@end
Copy the code

TypeEncoding records all of the method’s parameter types, including the return value and input parameter types. ReturnType holds typeEncoding for return value types, argumentTypes for method input types.

YYClassPropertyInfo module

@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct @property (nonatomic, strong, readonly) NSString *name; ///< property's name
@property (nonatomic, assign, readonly) YYEncodingType type;      ///< property's type @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
@property (nonatomic, strong, readonly) NSString *ivarName;       ///< property's ivar name @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil @property (nullable, nonatomic, strong, readonly) NSArray
      
        *protocols; ///< may nil @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull) @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) /** Creates and returns a property info object. @param property property opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithProperty:(objc_property_t)property; @end
      Copy the code

– (instanceType)initWithProperty:(objc_property_t)property method is used to complete the assignment of several properties to save property information. Let’s look at the implementation

- (instancetype)initWithProperty:(objc_property_t)property {//property is returned if the property is emptyif(! property)returnnil; self = [super init]; // Save property _property = property; // save name const char *name = property_getName(property);if(name) { _name = [NSString stringWithUTF8String:name]; } /*** save the attribute type ***/ YYEncodingTypetype = 0;
    unsigned int attrCount;
    objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
    for (unsigned int i = 0; i < attrCount; i++) {
        switch (attrs[i].name[0]) {
            case 'T': { // Type encoding
                if(attrs[I].value) {// SavetypeEncoding
                    _typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
                    type = YYEncodingGetType(attrs[i].value);
                    
                    if ((type&yyenCodingTypemask) == YYEncodingTypeObject && _typeEncoding.length) {// Save the class type NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];if(! [scanner scanString:@"@ \" " intoString:NULL]) continue;
                        
                        NSString *clsName = nil;
                        if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\" <"] intoString:&clsName]) {
                            if(clsName.length) _cls = objc_getClass(clsName.UTF8String); } // Save protocol type NSMutableArray *protocols = nil;while ([scanner scanString:@"<" intoString:NULL]) {
                            NSString* protocol = nil;
                            if ([scanner scanUpToString:@">" intoString: &protocol]) {
                                if (protocol.length) {
                                    if(! protocols) protocols = [NSMutableArray new]; [protocols addObject:protocol]; } } [scanner scanString:@">"intoString:NULL]; } _protocols = protocols; }}}break; // Save the modifiers belowcase 'V': { // Instance variable
                if(attrs[i].value) { _ivarName = [NSString stringWithUTF8String:attrs[i].value]; }}break;
            case 'R': {
                type |= YYEncodingTypePropertyReadonly;
            } break;
            case 'C': {
                type |= YYEncodingTypePropertyCopy;
            } break;
            case '&': {
                type |= YYEncodingTypePropertyRetain;
            } break;
            case 'N': {
                type |= YYEncodingTypePropertyNonatomic;
            } break;
            case 'D': {
                type |= YYEncodingTypePropertyDynamic;
            } break;
            case 'W': {
                type |= YYEncodingTypePropertyWeak;
            } break;
            case 'G': {
                type |= YYEncodingTypePropertyCustomGetter;
                if(attrs[i].value) { _getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]); }}break;
            case 'S': {
                type |= YYEncodingTypePropertyCustomSetter;
                if(attrs[i].value) { _setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]); / /}}break; commented for code coverage in next line
            default: break; }}if (attrs) {
        free(attrs);
        attrs = NULL;
    }
    
    _type = type; // Save getter, setter methodsif (_name.length) {
        if(! _getter) { _getter = NSSelectorFromString(_name); }if(! _setter) { _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]); }}return self;
}

@end
Copy the code

The basic information of the attribute is stored

YYClassInfo module

@interface YYClassInfo : NSObject
@property (nonatomic, assign, readonly) Class cls; ///< class object
@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
@property (nullable, nonatomic, assign, readonly) Class metaCls;  ///< class's meta class object
@property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class
@property (nonatomic, strong, readonly) NSString *name; ///< class name
@property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos; ///< ivars
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos; ///< methods
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos; ///< properties

/**
 If the class is changed (for example: you add a method to this class with
 'class_addMethod()'), you should call this method to refresh the class info cache.
 
 After called this method, `needUpdate` will returns `YES`, and you should call 
 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
 */
- (void)setNeedUpdate;

/**
 If this method returns `YES`, you should stop using this instance and call
 `classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
 
 @return Whether this class info need update.
 */
- (BOOL)needUpdate;

/**
 Get the class info of a specified Class.
 
 @discussion This method will cache the class info and super-class info
 at the first access to the Class. This method is thread-safe.
 
 @param cls A class.
 @return A class info, or nil if an error occurs.
 */
+ (nullable instancetype)classInfoWithClass:(Class)cls;

/**
 Get the class info of a specified Class.
 
 @discussion This method will cache the class info and super-class info
 at the first access to the Class. This method is thread-safe.
 
 @param className A class name.
 @return A class info, or nil if an error occurs.
 */
+ (nullable instancetype)classInfoWithClassName:(NSString *)className;

@end
Copy the code

Class attributes are the basic information of the class, using the classInfoWithClass method to implement the assignment to save the class information. Among them, ivarInfos, methodInfos and propertyInfos are the elements YYClassIvarInfo, YYClassMethodInfo and YYClassPropertyInfo in the dictionary. YYClassInfo stores the class name, superclass, metaclass, and member variables, attributes, and methods of the class. The setNeedUpdate method sets the information for the class to be updated. The needUpdate method returns information about whether or not the class needs to be updated. ClassInfoWithClassName gets information about the class based on the class name. Now let’s look at the implementation.

@implementation YYClassInfo {// use to check whether we need to update class information BOOL _needUpdate; } - (instancetype)initWithClass:(Class) CLS {// CLS returns nil if it is emptyif(! cls)returnnil; self = [super init]; // save CLS _cls = CLS; // Save superCls _superCls = class_getSuperclass(CLS); _isMeta = class_isMetaClass(CLS);if(! _metaclass = objc_getMetaClass(class_getName(CLS)); } // save class name _name = NSStringFromClass(CLS); // Update class information (ivar, method, property) [self _update]; _superClassInfo = [self. Class classInfoWithClass:_superCls];returnself; } /** update class ivar, method, property */ - (void)_update {// set null _ivarInfos = nil; _methodInfos = nil; _propertyInfos = nil; CLS = self.cls; ***/ unsigned int methodCount = 0; Method *methods = class_copyMethodList(CLS, &methodCount);ifNSMutableDictionary *methodInfos = [NSMutableDictionary new]; _methodInfos = methodInfos;for(unsigned int i = 0; i < methodCount; YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[I]]; // Use methodInfos to save the method informationif(info.name) methodInfos[info.name] = info; } // Free the methods object (because it is an object of C, we need to free it manually); } /*** 2. Save property information ***/ unsigned int propertyCount = 0; Objc_property_t *properties = class_copyPropertyList(CLS, &propertyCount);if(properties) { NSMutableDictionary *propertyInfos = [NSMutableDictionary new]; _propertyInfos = propertyInfos; // Iterate over the propertys listfor(unsigned int i = 0; i < propertyCount; I++) {/ / for each property information YYClassPropertyInfo * info = [[YYClassPropertyInfo alloc] initWithProperty: properties [I]]. // Save each property information with propertyInfosif(info.name) propertyInfos[info.name] = info; } // Release the prpperties object (since it is an object of C, we need to release it manually) free(properties); } /*** 3. Save ivar information ***/ unsigned int ivarCount = 0; *ivars = class_copyIvarList(CLS, &ivarCount);if(ivars) { NSMutableDictionary *ivarInfos = [NSMutableDictionary new]; _ivarInfos = ivarInfos; // Iterate through the IVAR listfor(unsigned int i = 0; i < ivarCount; YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[I]]; // Use ivarInfos to save each IVAR informationif(info.name) ivarInfos[info.name] = info; } // Free the ivars object (because it is an object of C, we need to release it manually) free(ivars); }if(! _ivarInfos) _ivarInfos = @{};if(! _methodInfos) _methodInfos = @{};if(! _propertyInfos) _propertyInfos = @{}; Ivar, method, property = ivar, method, property = ivar, method, property = ivar, method, property = ivar, method, property = ivar; } - (void)setNeedUpdate {// Set the _needUpdate variable to YES, indicating that ivar, property, method information is updated. } - (BOOL)needUpdate {// Returns whether ivAR, property, method information needs to be updatedreturn_needUpdate; + (instancetype)classInfoWithClass:(Class) CLS {// CLS returns nil if CLS is emptyif(! cls)returnnil; Static CFMutableDictionaryRef classCache; static CFMutableDictionaryRef metaCache; static dispatch_once_t onceToken; static dispatch_semaphore_t lock; Dispatch_once (& onceToken ^ {/ / create two cache dictionary classCache = CFDictionaryCreateMutable (CFAllocatorGetDefault (), and 0. &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); Lock = dispatch_semaphore_create(1); }); // dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); // In thread-safe mode, check whether the current class is metaclass or not. If it is metaclass, fetch the metaCache cache. YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(CLS)? metaCache : classCache, (__bridge const void *)(cls)); // If the cache is available, determine whether the _needUpdate variable needs to be updated, and update it if necessaryif(info && info->_needUpdate) { [info _update]; } // Dispatch_semaphore_signal (lock);if(! Info = [[YYClassInfo alloc] initWithClass: CLS];if(info) {dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info)); dispatch_semaphore_signal(lock); }} // Return the class information (if there is a cache, directly take the cache. If there is no cache, create a class information object to store in the cache, and then return the modified object.returninfo; + (instancetype)classInfoWithClassName:(NSString *) ClassName {// get class CLS = from ClassName NSClassFromString(className); // Get the class information based on the classreturn [self classInfoWithClass:cls];
}

@end

Copy the code

This class implements more code, let’s analyze one by one.

  1. The classInfoWithClassName method and the classInfoWithClass method are the entry methods. The classInfoWithClassName method is called inside the classInfoWithClass method. So the classInfoWithClass method is the core method. ClassCache, metaCache, classCache, metaCache, classCache, metaCache, classCache, metaCache, classCache The _update method is also a core method, which we will parse later. If no cached class information is available, the class information is created (this is done by calling the initWithClass method, which will be parsed later) and cached in the corresponding cache dictionary. Finally the class information object is returned. This entry method has nested methods, classInfoWithClass has nested initWithClass, initWithClass has nested classInfoWithClass, The method classInfoWithClass is constantly called to get the parent information and cache it. You end the call if you get to the root class if you don’t find the parent class of NSObject you end the loop.

  2. _update (ivarInfos, _methodInfos, _propertyInfos); Finally, assign the _needUpdate variable to NO. The internal implementation of the method is commented out.

  3. InitWithClass this method saves the basic information of the class, and then calls _update method to update ivar, property, and method information. The current class information is already there (and is then cached by the caller) and the classInfoWithClass method is called to hold the parent class information (which is also cached).

conclusion

The above is about YYModel framework in YYClassInfo class source code analysis. This class achieves the basic information of the class and carries on the thread-safe cache, which makes the call faster and safer. From which we have a certain understanding of YYModel, while learning the relevant runTime knowledge, the method of related runTime see the next article.