Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.


Where are categories used?

How does Category work?

What is the difference between Category and Extension?

Is there a load method in Category? When is the load method called?

Can the load method inherit?

What is the difference between the load and initialize methods? They’re in the category

The order of the calls? And how they call each other when inheritance occurs?

Can you add member variables to a Category? If so, how do YOU add member variables to a Category?

Create a Person class, create a Person Eat class, create a Person Test class.

@interface Person : NSObject

- (void)run;

@end

@implementation Person

- (void)eat

{

    NSLog(@"eat");

}

@end

Copy the code
@interface Person (Eat) <NSCopying, NSCoding>

- (void)eat;

@property (assign, nonatomic) int weight;

@property (assign, nonatomic) double height;


@end

@implementation Person (Eat)

- (void)eat
{
    NSLog(@"eat");

}
@end

Copy the code
@interface Person (Test) 

- (void)test;

@end


@implementation Person (Test)


- (void)test

{

    NSLog(@"test");

}
@end
Copy the code
Person *person = [[Person alloc] init];

[person run];

[person test];

[person eat];

Copy the code

When we call a method, we send a message.

Person calls the run method, which is

objc_msgSend(person, @selector(run));

Earlier we said that ISA and object instance methods are in class objects. The run method is clearly known in the person object’s class object’s list of methods…

So the test method, the eat method is the classification method, where do they go?

Does classification also have a class object ???? Are the object methods that we classify in the corresponding class object?

The answer is no. A class always has only one class object. No class object exists.

So where does the test method eat end up?

Where is it? ??????

In fact, when the program eventually runs, the run method, the test method, the eat method, whether it’s 1 category or 100 categories, it’s all going to merge

In a class object. Exists in the class object’s method list… In the list of methods on the Person object…

No matter which method you call, you end up looking for the class object through the Instance object’s ISA and calling it… This is a conclusion that will be proved later.


So where do the class methods in classification exist? Similarly, regardless of whether there is a single class or 100 classes, the class methods in that class will eventually be merged into a metaclass object and stored in the list of methods in the metaclass’s class object. That’s the conclusion. I’ll prove it later.

So when do you merge methods from a class into a class? At compile time? Or is it running?

The runtime is used at runtime, and it’s merged as the program is running.

The = = = = = = = = = =

What is the nature of compiled classification?

Locate the folder where Person+ test.m is located.

Type xcrun-sdk iphoneOS clang-arch arm64-rewrite-objc Person+ test.m

View the generated Person+ test.cpp file

struct _category_t { const char *name; Struct _class_t * CLS; // class const struct _method_list_t *instance_methods; Const struct _method_list_t *class_methods; Const struct _protocol_list_t *protocols; Struct _prop_list_t *properties const struct _prop_list_t *properties; A property in a class is just a method declaration, no method implementation. Also does not generate member variables)};Copy the code

Find the underlying structure after the classification is compiled.

Before the program runs, your classification method exists in the structure of the classification.

When the program runs, the runtime merges the methods from the list of methods in the classification structure into the list of methods on the class object.

Let’s find this compiled code again:

static struct _category_t _OBJC_$_CATEGORY_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) =

{

"Person",

0, // &OBJC_CLASS_$_Person,

(const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test,

(const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Test,

0,

0,

};
Copy the code

Assign a value to the classification structure.

We see assigning values to the five fields of the classification.

OBJC_CATEGORY_INSTANCE_METHODS_Person__Test (const struct _method_list_t *)&OBJC_CATEGORY_INSTANCE_METHODS_Person__Test

The compiled source we found looks like this:

static struct /*_method_list_t*/ {

unsigned int entsize;  // sizeof(struct _objc_method)

unsigned int method_count;

struct _objc_method method_list[1];

} _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) = {

sizeof(_objc_method),

1,

{{(struct objc_selector *)"test", "v16@0:8", (void *)_I_Person_Test_test}}

};

Copy the code

Do you see a test? Yes, that’s our test method.