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 <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)
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值