前語(yǔ)
在開(kāi)發(fā)中難免使用到NSTimer,為了避免循環(huán)引用,可能會(huì)在willDismiss來(lái)進(jìn)行釋放,置為nil;不過(guò)經(jīng)過(guò)查閱大神資料,有更好的解決方法:NSProxy;
下面來(lái)介紹一下
實(shí)現(xiàn)
先上代碼:MyTimerProxy.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MyTimerProxy : NSObject
@property (nonatomic, weak) id target;
+ (instancetype)initWithTarget:(id)target;
@end
MyTimerProxy.m
//
// MyTimerProxy.m
// Test-OC
//
// Created by Old.Wang on 2020/11/9.
// Copyright ? 2020 Old.Wang. All rights reserved.
//
#import "MyTimerProxy.h"
@implementation MyTimerProxy
+ (instancetype)initWithTarget:(id)target{
MyTimerProxy * proxy = [[MyTimerProxy alloc] init];
proxy.target = target;
return proxy;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
if ([self.target respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:self.target];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
return [self.target methodSignatureForSelector:aSelector];
}
@end
Controller層使用以及日志
#import "ViewController.h"
#import "MyTimerProxy.h"
@interface ViewController ()
@property (nonatomic, strong) NSTimer * t_timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
MyTimerProxy *myProxy = [MyTimerProxy initWithTarget:self];
self.t_timer = [NSTimer timerWithTimeInterval:3 target:myProxy selector:@selector(runTimer) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.t_timer forMode:NSRunLoopCommonModes];
}
#pragma mark - timer
- (void)runTimer{
NSLog(@"Runing %s",__func__);
}
#pragma mark - Dealloc
- (void)dealloc{
[self.t_timer invalidate];
self.t_timer = nil;
NSLog(@"%s",__func__);
}
@end
離開(kāi)頁(yè)面棧后,最后打印日志為:[viewController dealloc],對(duì)象釋放;
原理

NSProxy解決循環(huán)引用原理圖.png
實(shí)際上通過(guò)弱化self - target 的強(qiáng)引用關(guān)系來(lái)解決引用環(huán)。