iOS内存优化之NSTimer存在的内存泄漏

  最近开始进行内存优化了,先从NSTimer的内存泄漏做起,NSTimer的造成内存泄漏的主要原因就是循环引用,NSTimer如果只响应一次的话是不存在循环引用的。主要是repeat为YES时才存在循环引用。其中timer需要执行必须要加到runloop中才可以,schedule开头的方法默认加入了NSdefaultModel了,但是加入runloop会对timer进行一个强持有。timer的target也会被timer强持有,造成target的dealloc不会被触发
循环主要有两种方式

1,定时器响应为block时,需要配合@weakify(),@strongify()来消除循环引用
2, 定时器响应为selector时。需要中介者来作为timer的target,timer触发的方法被转发给真正的target这样就OK了。

参考博客地址:NSTimer避坑指南
非常感谢作者详细的分析,大家可以多多的关注作者,多多支持。
根据作者的文章,我这边对通过中介者对NSTimer进行了优化,主要是优化有两点就是NSTimer的响应为selector时,不存在循环引用了,并且NSTimer会自动释放,不需要开发者手动释放,NSTimer响应为block时,仍然用@weakify(),@strongify()来避免循环引用,但是NSTimer可以自动释放,不用开发者自己手动去释放了。
具体代码如下:

import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSTimer (JKBasicProvider)
/**
 普通定时器,自动加入Default类型的runloop中
 */
+ (NSTimer *)jk_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                        target:(id)target
                                        repeat:(BOOL)repeat
                                         block:(void(^)(NSTimer *timer))block;

/**
 普通定时器,需要手动添加至runloop中
 */
+ (NSTimer *)jk_timerWithTimeInterval:(NSTimeInterval)interval
                               target:(id)target
                               repeat:(BOOL)repeat
                                block:(void(^)(NSTimer *timer))block;

/**
普通定时器,自动加入Default类型的runloop中
*/
+ (NSTimer *)jk_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                        target:(id)target
                                      selector:(SEL)selector
                                      userInfo:(nullable id)userInfo
                                       repeats:(BOOL)repeat;

/**
 普通定时器,需要手动添加至runloop中,可以进行暂停,重启操作
 */
+ (NSTimer *)jk_timerWithTimeInterval:(NSTimeInterval)interval
                               target:(id)target
                             selector:(SEL)selector
                             userInfo:(nullable id)userInfo
                              repeats:(BOOL)repeat;
@end
#import "NSTimer+JKBasicProvider.h"

@interface JKTimerTarget : NSObject

@property (nonatomic,weak) id actionTarget;
@property (nonatomic,copy) void(^actionBlock)(NSTimer *timer);
@property (nonatomic, assign) SEL actionSelector;

@end

@implementation JKTimerTarget

- (instancetype)initWithSelector:(SEL)aSelector
                    actionTarget:(id)actionTarget
{
    self = [super init];
    if (self) {
        self.actionBlock = nil;
        self.actionTarget = actionTarget;
        self.actionSelector = aSelector;
    }
    return self;
}

- (instancetype)initWithBlock:(void(^)(NSTimer *timer))block
                 actionTarget:(id)actionTarget{
    self = [super init];
    if (self) {
        self.actionBlock = block;
        self.actionTarget = actionTarget;
    }
    return self;
}

- (void)timerAction:(NSTimer *)timer{
    if (self.actionTarget == nil) {
        [timer invalidate];
        timer = nil;
    }else{
        if (self.actionBlock) {
            self.actionBlock(timer);
        }else{
            IMP imp = [self.actionTarget methodForSelector:self.actionSelector];
            void (*func)(id, SEL,NSTimer *) = (void *)imp;
            func(self.actionTarget, self.actionSelector,timer);
        }
    }
}

@end


@implementation NSTimer (JKBasicProvider)

+ (NSTimer *)jk_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                        target:(id)target
                                        repeat:(BOOL)repeat
                                         block:(void(^)(NSTimer *timer))block
{
    JKTimerTarget *timerTarget = [[JKTimerTarget alloc] initWithBlock:block actionTarget:target];
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:interval target:timerTarget selector:@selector(timerAction:) userInfo:nil repeats:repeat];
    return timer;
}


+ (NSTimer *)jk_timerWithTimeInterval:(NSTimeInterval)interval
                               target:(id)target
                               repeat:(BOOL)repeat
                                block:(void(^)(NSTimer *timer))block
{
    JKTimerTarget *timerTarget = [[JKTimerTarget alloc] initWithBlock:block actionTarget:target];
    NSTimer *timer = [NSTimer timerWithTimeInterval:interval target:timerTarget selector:@selector(timerAction:) userInfo:nil repeats:repeat];
    return timer;
}

+ (NSTimer *)jk_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                        target:(id)target
                                      selector:(SEL)selector
                                      userInfo:(nullable id)userInfo
                                       repeats:(BOOL)repeat
{
  JKTimerTarget *timerTarget = [[JKTimerTarget alloc] initWithSelector:selector actionTarget:target];
    NSTimer *timer = [NSTimer timerWithTimeInterval:interval target:timerTarget selector:@selector(timerAction:) userInfo:userInfo repeats:repeat];
    return timer;
}


+ (NSTimer *)jk_timerWithTimeInterval:(NSTimeInterval)interval
                               target:(id)target
                             selector:(SEL)selector
                             userInfo:(nullable id)userInfo
                              repeats:(BOOL)repeat
{
    JKTimerTarget *timerTarget = [[JKTimerTarget alloc] initWithSelector:selector actionTarget:target];
    NSTimer *timer = [NSTimer timerWithTimeInterval:interval target:timerTarget selector:@selector(timerAction:) userInfo:userInfo repeats:repeat];
    return timer;
}

由于内容较少,就没有单独给大家封装成库,大家可以直接复制粘贴使用。
更多技术干货文章可以扫描下方二维码:
在这里插入图片描述

发布了231 篇原创文章 · 获赞 110 · 访问量 60万+

猜你喜欢

转载自blog.csdn.net/HHL110120/article/details/102513436