iOS-解决NSTimer强引用

前言

NSTimer的官方文档对于target的解释,The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.意思就是会对target强引用,直到timer被invalidated掉。

 

场景:

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f target:self selector:@selector(update:) userInfo:nil repeats:YES];控制器强引用timer,timer强引用控制器,造成循环引用,导致控制器无法释放造成内存泄露。

 

weakSelf:

__weak typeof(self) weakSelf = self;

    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f target:weakSelf selector:@selector(update:) userInfo:nil repeats:YES];

这种简单的方式,并不能打破timer和控制器之间的循环引用,也就是说weakSelf和strongSelf在这里的唯一区别:就是self被释放了,target会变成nil。

 

NSProxy构建中间target:

DYLWeakProxy对target进行弱引用,然后通过消息转发,最后的执行者转发至targetObject,因为target是弱引用,因此不会造成循环引用。

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f target:[DYLWeakProxy weakProxyForObject:self] selector:@selector(update:) userInfo:nil repeats:YES];

#import <Foundation/Foundation.h>

@interface DYLWeakProxy : NSProxy

+ (instancetype)weakProxyForObject:(id)targetObject;

@end


#import "DYLWeakProxy.h"

@interface DYLWeakProxy ()

@property (weak, nonatomic) id targetObject;

@end

@implementation DYLWeakProxy

+ (instancetype)weakProxyForObject:(id)targetObject
{
    DYLWeakProxy *weakObject = [DYLWeakProxy alloc];
    weakObject.targetObject = targetObject;
    return weakObject;
}

#pragma mark - Forwarding Messages

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.targetObject;
}


#pragma mark - NSWeakProxy Method Overrides
#pragma mark - Handling Unimplemented Methods

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
   return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{    
    void *nullPointer = NULL;
    [invocation setReturnValue:&nullPointer];
}

@end

 

CADisplayLink:

同样的,CADisplayLink也会因为强引用target,从而造成循环引用,解决这个问题与NSTimer类似,依然可以DYLWeakProxy解决;其实加载gif的第三方FLAnimatedImage也使用该方法解决循环引用的问题。

CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:[DYLWeakProxy weakProxyForObject:self] selector:@selector(update:)];

 

最后

除了NSTimer定时器和CADisplayLink外,GCD也可以创建定时器(我封装的DYLDispatchTimerButton倒计时用的就是GCD定时器),而且不存在循环应用的问题以及RunLoop的问题,NSTimer默认情况下运行在NSDefaultRunLoopMode模式下,因此为了防止滚动视图在滚动过程中NSTimer也能正常运行,会通过设置NSRunLoopCommonModes标记,自动的将NSTimer加入到带有CommonMode标记的模式下,即NSDefaultRunLoopMode和NSEventTrackingRunLoopMode。

转载于:https://my.oschina.net/u/1450995/blog/912311

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值