1、定时器无法释放问题
当使用定时器的时候,下面的情况,定时器是无法释放的
#import "TimeVC.h"
#import "Temp.h"
#import "JHProxy.h"
@interface TimeVC ()
@property (strong, nonatomic) CADisplayLink *link;
@property (strong, nonatomic) NSTimer *timer;
@end
@implementation TimeVC
- (void)viewDidLoad {
[super viewDidLoad];
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
}
- (void)timerTest {
NSLog(@"%s",__func__);
}
- (void)linkTest {
NSLog(@"%s",__func__);
}
- (void)dealloc {
[self.link invalidate];
self.link = nil;
[self.timer invalidate];
self.timer = nil;
NSLog(@"%s",__func__);
}
@end
内存无法释放原因分析:
解决方案:搞一个中间类,弱引用控制器
2、内存释放方法一
写一个中间类
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Temp : NSObject
@property (weak, nonatomic) id target;
+ (id)proxyWithTarget:(id)target;
@end
NS_ASSUME_NONNULL_END
实现消息转发
#import "Temp.h"
@implementation Temp
+ (instancetype)proxyWithTarget:(id)target {
Temp *tempProxy = [[Temp alloc] init];
tempProxy.target = target;
return tempProxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
return self.target;
}
@end
调用方法:
- (void)viewDidLoad {
[super viewDidLoad];
self.link = [CADisplayLink displayLinkWithTarget:[Temp proxyWithTarget:self] selector:@selector(linkTest)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Temp proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}
3、内存释放方法一
使用NSProxy类,代理类,天生就是用来做代理的类
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface JHProxy : NSProxy
@property (weak, nonatomic) id target;
+ (id)proxyWithTarget:(id)target;
@end
NS_ASSUME_NONNULL_END
#import "JHProxy.h"
@implementation JHProxy
+ (instancetype)proxyWithTarget:(id)target {
JHProxy *tempProxy = [JHProxy alloc];
tempProxy.target = target;
return tempProxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end
调用方法:
- (void)viewDidLoad {
[super viewDidLoad];
self.link = [CADisplayLink displayLinkWithTarget:[JHProxy proxyWithTarget:self] selector:@selector(linkTest)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[JHProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}
总结:尽量使用NSProxy,因为它的功能就是用来消息转发的,不会有第一阶段和第二阶段(参考消息转发机制3大阶段)
4. Swift
Swift中用不了NSProxy
class WeakProxy: NSObject {
weak var target: NSObjectProtocol?
var sel: Selector?
public required init(target:NSObjectProtocol?, sel: Selector?) {
self.target = target
self.sel = sel
super.init()
guard target?.responds(to: sel) == true else {
return
}
let method = class_getInstanceMethod(self.classForCoder, #selector(WeakTimerProxy.redirectionMethod))!
class_replaceMethod(self.classForCoder, sel!, method_getImplementation(method), method_getTypeEncoding(method))
}
@objc func redirectionMethod() {
if self.target != nil {
self.target?.perform(self.sel)
}
}
}