iOS底层系列之<45>--内存管理<1>NSProxy的使用
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 NS_ASSUME_NONNULL_BEGIN@interface Temp : NSObject
@property (weak, nonatomic) id target;
+ (id)proxyWithTarget:(id)target;
@endNS_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 NS_ASSUME_NONNULL_BEGIN@interface JHProxy : NSProxy
@property (weak, nonatomic) id target;
+ (id)proxyWithTarget:(id)target;
@endNS_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 = targetself.sel = selsuper.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)}}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
