How OC implements multiple inheritance

When single inheritance is not enough and it is difficult to model the problem domain, we usually think of multiple inheritance directly. Multiple inheritance is the ability to derive classes from more than one direct base class, which can model applications more directly. However, Objective-C does not support multiple inheritance. Because the message mechanism name lookup occurs at runtime rather than at compile time, it is difficult to solve the ambiguity that may be caused by multiple base classes. But in fact, Objective-C does not need to support multiple inheritance. We can find the following methods to achieve multiple inheritance indirectly:

**Message forwarding**
**delegate and protocol **
**category**

Message forwarding

When a message is sent to someObject, but the runtime system cannot find the implementation of the corresponding method in the current class and the parent class, the runtime system will not immediately report an error to cause the program to crash, but perform the following steps in sequence:

 

Briefly describe the process separately:

1. Dynamic method analysis: send resolveInstanceMethod: signal to the current class to check whether a method is dynamically added to the class. (If you are confused, please search: @dynamic)
2. Fast message forwarding: Check whether the class implements the forwardingTargetForSelector: method, if it is implemented, call this method. If the return value object of this method is not nil or self, the message will be resent to the return object.
3. Standard message forwarding: runtime sends methodSignatureForSelector: message to obtain the method signature corresponding to the Selector. If the return value is not empty, the message will be forwarded through forwardInvocation:, and if the return value is empty, the doesNotRecognizeSelector: message will be sent to the current object, and the program will crash and exit.

As the name implies, we can use the 2 and 3 methods in the above process to complete message forwarding.

Fast message forwarding

The implementation method of fast message forwarding is very simple, just need to rewrite-(id)forwardingTargetForSelector:(SEL)aSelector method.
Let me give a simple example. For example, there are two existing classes: Teacher and Doctor. Doctor can perform surgery (operate method).

@interface Teacher : NSObject   
  
@end   
@interface Doctor : NSObject   
   
- (void)operate;   
@end   

Through fast message forwarding, it is easy for the teacher to call the doctor's method for surgery.

The Teacher class needs to forward the message to the Doctor:

- (id)forwardingTargetForSelector:(SEL)aSelector   
{   
   Doctor *doctor = [[Doctor alloc]init];   
   if ([doctor respondsToSelector:aSelector]) {   
       return doctor;   
   }   
   return nil;   
}   

Although the message can be forwarded and transmitted dynamically, the static check of the editor cannot be bypassed. Then the question is, how to declare it since the Teacher class does not implement the operate method?
So far, I only thought of the following two methods:

Declaration method 1 ———— Category

@interface Teacher (DoctorMethod)   
- (void)operate;   
  
@end   

Declaration method 2 ———— Import header file, force type conversion when calling

The Teacher header file needs to include the Doctor header file, telling the compiler to find the declaration of the operator method in Doctor.h, and force the type to be changed when calling.

Teacher *teacher = [[Teacher alloc]init];   
[(Doctor *)teacher operate];   

If you are interested, you can think about a question: If you convert its type to id, you can also compile and pass it and realize forwarding. But what hidden dangers will it bring?

Method 1 uses categories that are clear and simple enough, so why propose method 2? My thought is that the drawback of Method 1 is that the method thrown out is fixed and exposed in .h; Method 2 is relatively flexible and hides the message I want to forward.

Standard message forwarding
Standard message forwarding needs to rewrite the methodSignatureForSelector: and forwardInvocation: two methods.
The sending process is shown in the figure:

 

Forward rewriting method:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector   
{   
    NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];   
    if (signature==nil) {   
        signature = [someObj methodSignatureForSelector:aSelector];   
    }   
    NSUInteger argCount = [signature numberOfArguments];   
    for (NSInteger i=0 ; i

    }   
       
    return signature;   
}   
 
- (void)forwardInvocation:(NSInvocation *)anInvocation   
{   
    SEL seletor = [anInvocation selector];   
    if ([someObj respondsToSelector:seletor]) {   
        [anInvocation invokeWithTarget:someObj];   
    }   
       
}   

Comparison of two message forwarding methods

Fast message forwarding: simple, fast, but can only be forwarded to one object.
Standard message forwarding: slightly more complicated and slower, but the forwarding operation is controllable, and multi-object forwarding can be realized.

delegate和protocol

Delegation is the most commonly used callback mechanism in Objective-C. Usage I don't think there is much to say. To sum up the characteristics of the mechanism: the
delegation assists the main body to complete the operation task, and the operation that needs to be customized is reserved for the delegate object to customize the implementation, similar to the subclassing main body.
In addition, it can be used as event listener.
I can't think of it for a while...

Category I
personally think that category is one of the essence of Objective-C design, and it is also the biggest reason why I love Objective-C.

The category is a powerful thing, it can add methods to the class, you can also add instances. There must be many people who disagree and want to remind me: One of the limitations of categories is that they cannot add new instance variables to the class. Endorsement is really ruining, listen to me give an example and speak slowly.

Let's re-create the Teacher class:

@interface Teacher : NSObject   
{   
    NSUInteger age;   
}   
   
@end   

Only an age is not enough to describe the teacher, I want to add a profession instance to save the teacher's profession. The intuitive idea is to subclass Teacher, in fact, you can also use categories.

You need to understand runtime programming knowledge, pay attention to objc_setAssociatedObject and objc_getAssociatedObject.

//   
//  Teacher+Profession.m   
//     
  
#import "Teacher+Profession.h"   
#import   

  
const char *ProfessionType = "NSString *";   
@implementation Teacher (Profession)   
  
-(void)setProf:(NSString*)prof   
{   
   objc_setAssociatedObject(self, ProfessionType, prof, OBJC_ASSOCIATION_RETAIN_NONATOMIC);   
}   
  
-(NSString *)prof   
{   
   NSString *pro = objc_getAssociatedObject(self, ProfessionType);   
   return pro;   
}   
  
@end   

Now you can access the teacher's profession value through setProf: and prof.



Author: ScaryMonsterLyn
link: https: //www.jianshu.com/p/c473b41c083d

Guess you like

Origin blog.csdn.net/wangletiancsdn/article/details/97629933