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

Today we’ll look at a third way to break target’s strong hold

NSProxy virtual base class

NSProxy functions:

  • OC does not support multiple inheritance, but it is based on a runtime mechanism that can be implemented through NSProxy
  • NSProxy and NSObject belong to the same class, or virtual class, that implements only the protocol part of NSObject
  • NSProxy is essentially an abstract class encapsulated by message forwarding, similar to an agent

You can implement message forwarding by inheriting NSProxy and rewriting the following two methods

- (void)forwardInvocation:(NSInvocation *)invocation; 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
Copy the code

In addition to being used for multiple inheritance, NSProxy can also be used as an intermediary to cut off strong holding. Open lgproxy.h and write the following code:

#import <Foundation/Foundation.h> 

@interface LGProxy : NSProxy

+ (instancetype)proxyWithTransformObject:(id)object; 

@end
Copy the code

Open lgproxy. m and write the following code:

#import "LGProxy.h" @interface LGProxy() @property (nonatomic, weak) id object; @end @implementation LGProxy + (instancetype)proxyWithTransformObject:(id)object{ LGProxy *proxy = [LGProxy alloc]; proxy.object = object; return proxy; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ if (! Self. object) {NSLog(@" exception collection -stack"); return nil; } return [self.object methodSignatureForSelector:sel]; } - (void)forwardInvocation:(NSInvocation *)invocation{ if (! Self. object) {NSLog(@" exception collection -stack"); return; } [invocation invokeWithTarget:self.object]; } @endCopy the code

LGProxy call code:

- (void)viewDidLoad { 
    [super viewDidLoad];
    
    self.proxy = [LGProxy proxyWithTransformObject:self];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(fireHome) userInfo:nil repeats:YES];
} 

- (void)fireHome{ 
    num++; 
    NSLog(@"hello word - %d",num); 
}

- (void)dealloc{
    [self.timer invalidate]; 
    self.timer = nil; 
}
Copy the code
  • LGProxy initializes the method that assigns the passed object to the weakly referenced object
  • And then in UIViewController, create the LGProxy object proxy. Create an NSTimer object and pass the proxy to target to prevent NSTimer from holding the ViewController too strongly.
  • LGProxy’s message forwarding method is triggered when NSTimer is called back
    • MethodSignatureForSelector: set up the method signature
    • ForwardInvocation: The message is forwarded to Object without service processing
  • When the page exits, the ViewController can be released normally
    • And then in dealloc, release the NSTimer. In this case, NSTimer strongly holds contact with the proxy, and the proxy is also released