There is a video in WWDC2020 about some optimization of Objective-C at runtime. This article explores some knowledge points mentioned in the video.
If you are interested, you can take a look at this video or my last article: about the improvement of WWDC2020-Objective-C runtime.
Verify the points mentioned in the video:
1.class_ro_t stores Flags, Size, Name, Methods, Protocols, Ivars and Properties.
2.class_rw_t stores Methods, Protocols, and Properties.
3. Why_ ro_ T has stored Methods, Protocols, Properties, and class_rw_t also store these?
The introduction in WWDC is class_ro_t is read-only. The stored information has been determined at the compilation time and cannot be changed. It can be cleared when necessary. It's good to reload it in the disk when it needs to be used. class_rw_t is readable and writable. Its information is stored when it is running and written when it needs to be used, and it always exists in memory.
Among them, point 2 has been verified in the previous chapter. There are indeed method lists, protocol lists and attribute lists, but the protocol lists are not verified. After reading the following verification methods, verify the class_ rw_ The protocol method of T is the same.
First, we declare several classes, namely SHPerson inherited from NSObject, SHPerson(Home), the classification of SHPerson, and SHTeacher inherited from SHPerson.
#pragma mark: - SHPerson @interface SHPerson : NSObject { NSString *_name; NSString *_age; NSObject *family; } @property (nonatomic, copy) NSString *nickname; @end @implementation SHPerson - (void)play_basketball {} + (void)playFootball {} @end #Pragma mark: - Classification of shperson @interface SHPerson(Home) - (void)write_homework; + (void)eat; @end @implementation SHPerson(Home) - (void)write_homework {} + (void)eat {} @end #pragma mark: - SHTeacher @interface SHTeacher : SHPerson @property (nonatomic, strong) NSString *course; @end @implementation SHTeacher - (void)attend_class {} + (void)change_homework {} @end
(slide to show more)

1, class_ro_t memory structure
In class_ rw_ In T, there is such a method:
const class_ro_t *ro() const { auto v = get_ro_or_rwe(); if (slowpath(v.is<class_rw_ext_t *>())) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro; } return v.get<const class_ro_t *>(&ro_or_rw_ext); }
(slide to show more)
You can get the class by ro()_ ro_ Let's take a look at the data of T.

class_ ro_ There are member variables of Flags, Size, Name, Methods, Protocols, Ivars and Properties in T, but baseProtocols is nil. Let's add a protocol to SHPreson and run it again.
#pragma mark: - Protocol @protocol SHPersonProtocol<NSObject> - (void)run; - (void)sleep; + (void)work; @end #pragma mark: - SHPerson @interface SHPerson : NSObject<SHPersonProtocol> { NSString *_name; NSString *_age; NSObject *family; } @property (nonatomic, copy) NSString *nickname; @end @implementation SHPerson - (void)play_basketball {} + (void)playFootball {} /// SHPersonProtocol - (void)run {} - (void)sleep {} + (void)work {} @end
(slide to show more)
Let's Reprint:

Base protocols has value. Let's take a look at class in the source code_ ro_ Structure of T.


2, Class_ ro_ ivars of T
Let's take a look at class first_ ro_ What are the ivars of T:

There are indeed four member variables in SHPerson. If we add attributes or member variables to the classification, class_ ro_ Will t's ivars and baseProperties also be stored?

You can see that the syntax of adding instance variables to the category is not enough. Then we can only add attributes, but in fact, we can probably guess that adding attributes, even if the syntax is too high, class_ro_t will not be stored. Let's verify it first.

Adding a property in the classification requires adding the corresponding getter and setter.

When you are ready, let's verify:

With theout height attribute, our guess is correct! This is also the reason why attributes cannot be added to the classification. If you want to add attributes and use them normally, you need to use the associated object method.
3, Class_ ro_ baseMethodList of T
Let's take a look at the memory structure of baseMethodList:

We found that baseMethodList is a type of void *const. Remember the type of method list you learned earlier? method_list_t. We convert void *const to method_list_t * . Then print out the method_ list_ Method returned by get in t_ The big() method of T.

We find that the error is reported. Let's take a look at the implementation of big():
big &big() const { ASSERT(!isSmall()); return *(struct big *)this; }
(slide to show more)
Let's take another look at the comments of baseMethodList in the source code:

If it points to a small list, it is signed, but if it points to a large list, it may be unsigned.
Since big() doesn't work, try printing through name().

At this time, you will find that the method name is printed, and the baseMethodList also prints all instance methods in the classification and protocol!

4, class_ro_t's baseProtocols
Next, let's see if there are corresponding protocol methods in base protocols.

It seems that you can't see anything. Let's take a look at protocol_list_t's source code:
struct protocol_list_t { // count is pointer-sized by accident. uintptr_t count; protocol_ref_t list[0]; // variable-size size_t byteSize() const { return sizeof(*this) + count*sizeof(list[0]); } protocol_list_t *duplicate() const { return (protocol_list_t *)memdup(this, this->byteSize()); } typedef protocol_ref_t* iterator; typedef const protocol_ref_t* const_iterator; const_iterator begin() const { return list; } iterator begin() { return list; } const_iterator end() const { return list + count; } iterator end() { return list + count; } };
(slide to show more)
There is nothing in the source code, but the list is list[0] in the source code. Let's print out the list[0] and try:

Printed out is protocol_ref_t. Let's look at the protocol in the source code_ ref_ What structure is t

We found that protocol_ref_t is followed by a comment, protocol_ref_t is a protocol_t * type, let's take a look at the protocol_t structure in source code:

Isn't that what we want? Next, we use lldb to set the protocol_ref_t strong to protocol_t * and print:

There's exactly what we want. The next step is a meal:

Through verification, there are protocol methods in baseProtocols.
5, Class_ ro_ baseProperties of T
Next, let's see if there is our corresponding property information in baseProperties.

There is not only the nickname attribute, but also the height attribute in the classification and other attributes of the system.
6, firstSubclass
About why firstSubclass is nil, let's look at a lldb print:

7, Summary
class_rw_t stores information related to class instance methods, protocol methods, and attributes
class_ro_t stores flags (some other data, such as reference count related), class size, class name, class instance method list, protocol method list, member variables and attribute related information.
Source: rare earth Nuggets
Author: Coder_ Zhang San
Link: https://juejin.cn/post/7041911723128782855
- END -