iOS定时器循环引用问题解决

本文探讨了使用NSTimer时可能出现的循环引用问题,并提供了两种有效的解决方案。一种是通过创建一个代理类来间接引用目标对象,另一种是利用NSProxy类进行消息转发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们通常使用NSTimer或CADisplayLink会使用以下方式

//定义
@property (nonatomic, strong)NSTimer *timer;

//实现
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(showMsg) userInfo:nil repeats:YES];

//销毁
-(void)dealloc
{
    [self.timer invalidate];
}

因为控制器强引用了timer,timer又强引用了控制器,所以会产生循环引用。

尝试解决办法:

1、把timer改成弱引用
@property (nonatomic, weak)NSTimer *timer;

虽然控制器对timer是弱引用,但是控制的delloc方法依赖于timer的invalidate,timer的invalidate又依赖于控制器的delloc方法,依旧是循环引用;

2、使用 __weak
 __weak typeof(self) weakSelf = self;
 self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf selector:@selector(showMsg) userInfo:nil repeats:YES];

weak 关键字适用于block,当block引用了块外的变量时,会根据修饰变量的关键字来决定是强引用还是弱引用,如果变量使用weak关键字修饰,那block会对变量进行弱引用,如果没有__weak关键字,那就是强引用。

但是NSTimer的 scheduledTimerWithTimeInterval:target 方法内部不会判断修饰target的关键字,其内部会对target进行强引用,还是会产生循环引用。

最终解决办法

循环引用产生的原因就是因为A强引用B,同时B强引用A,那如果我们在A和B之间加一个C,让A强引用C,C弱引用B,B强引用A,那在B被释放后,A也会释放,就可以解决循环引用的问题;

解决方法1:

定义一个继承自NSObject的类HJProxy,在HJProxy中弱引用target

//HJProxy.h
@interface HJProxy : NSObject
+(instancetype)proxyWithTarget:(id)target;
@end


//HJProxy.m
#import "HJProxy.h"

@interface HJProxy()
@property (weak, nonatomic) id target;
@end

@implementation HJProxy

+(instancetype)proxyWithTarget:(id)target
{
    HJProxy *proxy = [[HJProxy alloc] init];
    proxy.target = target;
    return proxy;
}

//使用消息转发,将消息转发给控制器
-(id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.target;
}

@end
//ViewController.m

HJProxy1 *proxy = [HJProxy1 proxyWithTarget:self];

//将timer的target设置为proxy,proxy又弱引用了控制器,其实最终还是调用了控制器的showMsg方法。
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(showMsg) userInfo:nil repeats:YES];
解决方法2:

使用iOS的NSProxy类,NSProxy就是专门用来做消息转发的.

//HJProxy1.h
@interface HJProxy1 : NSProxy

+(instancetype)proxyWithTarget:(id)target;

@end

//HJProxy1.m
@interface HJProxy1()
@property (weak, nonatomic)id target;
@end

@implementation HJProxy1

+(instancetype)proxyWithTarget:(id)target
{
    HJProxy1 *proxy = [HJProxy1 alloc];
    proxy.target = target;
    return proxy;
}

-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.target methodSignatureForSelector:sel];
}

-(void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.target];
}

@end

转载于:https://my.oschina.net/mexiaobai1315/blog/1858635

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值