About iOS due NSTimer no way to release the memory problem of principle

About iOS due NSTimer no way to release the memory problem of principle

Look at the code related Countdown

#import "AViewController.h"

@interface AViewController ()
@property (nonatomic, strong) NSTimer * timer;
@property (nonatomic, assign) int timeCount;
@end

@implementation AViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown) userInfo:nil repeats:YES];
    // Do any additional setup after loading the view.
}
// 倒计时
-(void)countdown
{
    _timeCount ++;
    NSLog(@"-----%d-----",_timeCount);
    if (_timeCount >10) {
        [self.timer invalidate];
        self.timer = nil;
    }
}
-(void)dealloc
{
    NSLog(@"%s",__func__);
}


@end

As seen in the code, which is seen from the company's projects, such code is not looked at this issue and found that there AViewController memory controller at this time ctr exit


15063932-05eacf5b34375c20.png
AViewController.png

But there is not a solid line in Time held in the following, so I did not care
then hit a breakpoint in the dealloc after a long time and then see the implementation of


15063932-f7582317ec010ddb.png
dealloc.png

As Figure was seen timeRelease so I suspect the problem is NSTimer of
Ado
fact, which is an important reason is that NSTimer added to the system in the runLoop


15063932-e0d1d7f3212e4a02.png
Hold .png

Then someone would think of using weak modified look ctr, a good idea but in fact there is no effect, because the control of even the weak reference or references, weak references is to prevent a circular reference, but there is no figure above circular reference
solutions
using NSTimer the new api

/// Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire.
/// - parameter:  timeInterval  The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead
/// - parameter:  repeats  If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
/// - parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references
///创建并返回使用指定块对象初始化的新NSTimer对象。 这个计时器需要在运行循环(通过 -  [NSRunLoop addTimer:])之前安排,然后才能触发。
///  - 参数:timeInterval计时器触发之间的秒数。 如果seconds小于或等于0.0,则此方法选择非负值0.1毫秒
///  - 参数:重复如果是,则计时器将反复重新安排自己,直到无效。 如果为NO,计时器将在其触发后失效。
///  -  parameter:block计时器的执行体; 定时器本身在执行时作为参数传递给该块,以帮助避免循环引用
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

In fact, the new version of api has once again explained the reasons can not be released, but this can only be used after iOS10, before then iOS10 it?
I added a Category to NSTimer

#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN

@interface NSTimer (Category)

/**
 香哈私有Timer 使用

 @param seconds 间隔时间
 @param block 回调
 @param repeats 是否重复
 @return NSTimer
 */
+ (NSTimer *)skScheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;

/**
 香哈私有Timer 使用

 @param seconds 间隔时间
 @param block 回调
 @param repeats 是否重复
 @return NSTimer
 */
+ (NSTimer *)skTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;

@end

NS_ASSUME_NONNULL_END


#import "NSTimer+Category.h"

@implementation NSTimer (Category)
+ (void)skExecBlock:(NSTimer *)timer {
    if ([timer userInfo]) {
        void (^block)(NSTimer *timer) = (void (^)(NSTimer *timer))[timer userInfo];
        block(timer);
    }
}

+ (NSTimer *)skScheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
    return [NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(skExecBlock:) userInfo:[block copy] repeats:repeats];
}

+ (NSTimer *)skTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
    return [NSTimer timerWithTimeInterval:seconds target:self selector:@selector(skExecBlock:) userInfo:[block copy] repeats:repeats];
}

@end

This program is actually very simple is to join runLoop NSTimer NSTimer and ctr is so weak references, it will not affect its life cycle

15063932-0db117466709414d.png
block.png

Hope it helps you

Reproduced in: https: //www.jianshu.com/p/1303231098e2

Guess you like

Origin blog.csdn.net/weixin_33675507/article/details/91317266