Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity.

OC Basic principles of exploration document summary

introduce

NSProxy is essentially an abstract class that defines message forwarding capabilities.

  • NSProxy provides the message forwarding function
  • NSProxy and NSObject are sibling classes that do not inherit from NSObject
  • Implements the NSObject protocol

NSProxy的API

@interface NSProxy <NSObject> {__ptrAuth_objc_ISA_pointer Class isa; } // construct + (id)alloc; + (id)allocWithZone:(nullable NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE; + (Class)class; // message invocation - (void)forwardInvocation:(NSInvocation *)invocation; / / the method signature - (nullable NSMethodSignature *) methodSignatureForSelector: (SEL) SEL NS_SWIFT_UNAVAILABLE (" NSInvocation and related APIs not available"); - (void)dealloc; - (void)finalize; @property (readonly, copy) NSString *description; @property (readOnly, copy) NSString *debugDescription; + (BOOL)respondsToSelector:(SEL)aSelector; - (BOOL)allowsWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos); - (BOOL)retainWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);Copy the code

Description:

  • It can be seen from the class definition that only two methods are provided for message forwarding and method signature, which are used for message forwarding
  • And if you follow the NSObject protocol, you can do some basic things about your class

role

  • Message forwarding: NSProxy provides a method for message forwarding

  • Proxy: An implementation of message forwarding in a virtual base class can proxy other objects to implement certain functions.

  • Simulate multiple inheritance: A class that inherits from a virtual base class can represent multiple inheritance by proxying different objects while simultaneously implementing their respective methods

  • Mock polymorphism: A class that inherits from a virtual base class can be represented by different objects, and the same methods that implement them can represent different states called polymorphisms.

use

Define a proxy class WYProxy

For more details about the methods involved in signing and forwarding messages, see the section on forwarding messages in the OC Runtime official guidance document translation

@interface WYProxy () @property(nonatomic, weak, readonly) NSObject *objc; - (id)transformObjc:(NSObject *)objc{_objc = objc; return self; } // Proxy passed object + (instanceType)proxyWithObjc:(id)objc{return [[self alloc] transformObjc:objc]; } // return method signature /* This returns the method signature of the method that needs to be forwarded. So will return the object of the signature of the method * / - (NSMethodSignature *) methodSignatureForSelector: (SEL) SEL {NSMethodSignature * signature; if (self.objc) { signature = [self.objc methodSignatureForSelector:sel]; }else{ signature = [super methodSignatureForSelector:sel]; } return signature; - (void)forwardInvocation:(NSInvocation *)invocation{SEL SEL = [invocation selector];  if ([self.objc respondsToSelector:sel]) { [invocation invokeWithTarget:self.objc]; }}Copy the code

Description:

  • It does two things. One is to save the object to be proxied into a property of the proxied
  • The next step is to set up the message forwarding, which is all forwarded to objC

Define two classes WYPerson and WYStudent to be proxied

WYPerson:

@interface WYPerson : NSObject
- (void)eat;
@end

@implementation WYPerson
- (void)eat{
    NSLog(@"%s",__func__);
}
@end
Copy the code

WYStudent:

@interface WYStudent : NSObject
- (void)eat;
@end

@implementation WYStudent

- (void)eat{
    NSLog(@"%s",__func__);
}
@end
Copy the code

Message forwarding is implemented by proxy

/* WYProxy proxy WYStudent and WYPerson */ / */ - (void)proxyTest {WYPerson *person = [WYPerson alloc]; WYStudent *student = [WYStudent alloc]; WYProxy *proxy = [WYProxy alloc]; // proxy person [proxy transformObjc:person]; [proxy performSelector:@selector(eat)]; // proxy student [proxy transformObjc:student]; [proxy performSelector:@selector(eat)]; }Copy the code

Print result:

2021-11-08 22:02:27.349681+0800 NSProxy Virtual Class [12540:129438] -[WYPerson Eat] 2021-11-08 22:02:27.349792+0800 NSProxy virtual class [12540:129438] -[WYStudent eat]Copy the code

Description:

  • As you can see, we first add the objects we need to broker as our own properties
  • Then when the method is invoked, the proxy object internally forwards it all to the object that needs the proxy to implement it
  • And from this we also see that the proxy calls the same method but behaves differently, realizing the characteristics of polymorphism.
  • And proxy can implement WYPerson class method, also can implement WYStudent method, has the effect of multiple inheritance

A few questions

Can you do it with NSObject, message forwarding can be done with any class, why do you need to do it with NSProxy?

The NSObject class and its subclass override methods signature and message forward methods do not directly forward the message. Instead, they go through the message sending process, and if the message fails, the message is forwarded to notify the message recipient. So a lot more work will be done. Therefore, NSProxy can be used to forward messages more efficiently.

The details of the message sending process can be seen in the underlying analysis of the 03-OC method call, which shows that the process is complex and consumes little performance

In what situation can it be used at work?

  • Multiple inheritance
  • Section-oriented programming (polymorphic)
  • Resolve circular references (no strong references because it is called by message forwarding, not directly)