在为iOS设计应用程序时,我们需要一个可以轻松暂停和恢复的计时器。因此我们创建了自己的计时器。但是,它似乎泄漏,导致整个应用程序中的CPU使用率增加。下面是计时器的全部代码。任何帮助将不胜感激。此外,我们正在使用ARC,而且我们对这个概念不熟悉,因此我们可能会在某处导致保留周期。
@implementation PausibleTimer
{
BOOL hasPausedThisCycle;
}
+ (PausibleTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats
{
PausibleTimer *newTimer = [[PausibleTimer alloc] init];
newTimer.timeInterval = timeInterval;
newTimer.target = target;
newTimer.selector = selector;
newTimer.userInfo = userInfo;
newTimer.repeats = repeats;
return newTimer;
}
- (void)start
{
[self.timer invalidate]; // Invalidate current timer
// Initialize an NSTimer with the PausibleTimer conditions
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeInterval target:self selector:@selector(timerFired:) userInfo:self.userInfo repeats:self.repeats];
self.isPaused = NO; // Set isPaused to NO
}
- (void)pause
{
// If the timer is currently paused, return
if (self.isPaused)
{
return;
}
self.isPaused = YES; // Set isPaused to YES
hasPausedThisCycle = YES; // Set hasPausedThisCycle to YES
[self.timer invalidate]; // Invalidate current timer
}
- (void)timerFired:(NSTimer *)timer
{
// If the timer is currently paused, return
if (self.isPaused)
{
return;
}
// Ignore performSelector leaks
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if (self.selector)
{
[self.target performSelector:self.selector withObject:self];
}
else if (!self.selector)
{
[self invalidate];
}
#pragma clang diagnostic pop
if (hasPausedThisCycle)
{
hasPausedThisCycle = NO; // Set hasPausedThisCycle to NO
if (self.repeats)
{
// Set up a new NSTimer with original timeInterval
[self.timer invalidate];
[self start];
}
}
}
- (void)invalidate
{
[self.timer invalidate];
self.timer = nil;
self.selector = nil;
self.target = nil;
self.userInfo = nil;
}
@end
更新
这是头文件,显示了变量的声明。我从一开始就把目标设定为弱。从我使用乐器收集的内容,特别是时间分析器,它指向我的PausibleTimer并深入挖掘带我到mk_timer_arm的东西,据说我杀了我能做的一切之后仍然在运行。我在viewWillDisappear中使我的所有计时器无效并将其设置为nil。无论如何,这里是标题,我真的很感谢你的帮助。
#import <Foundation/Foundation.h>
@interface PausibleTimer : NSObject
// Set up NSTimer properties
@property (nonatomic) NSTimeInterval timeInterval;
@property (nonatomic, weak) id target;
@property (nonatomic) SEL selector;
@property (nonatomic) id userInfo;
@property (nonatomic) BOOL repeats;
@property (strong, nonatomic) NSTimer *timer; // Pointer to current timer
@property (nonatomic) BOOL isPaused; // Check if timer is paused
// PausibleTimer initializer
+ (PausibleTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats;
- (void)pause;
- (void)start;
- (void)invalidate;
@end
答案 0 :(得分:1)
您没有解释什么是泄漏,因此我将从您的代码中提出两个可能的考虑因素:
您没有显示实例变量的属性声明,但如果未明确声明self.target
weak
,那么您有一个保留周期和泄漏。假设我们想象一个具有PausibleTimer实例变量的视图控制器或类似对象。然后视图控制器保留PausibleTimer。但是PausibleTimer将视图控制器保留为target
。 Presto,保持周期,泄漏。
一般来说,ARC下的NSTimer存在很大问题。在无效之前,计时器会保留其目标。在这种情况下,NSTimer的目标是PausibleTimer实例。因此,如果PausibleTimer在拥有对象(视图控制器或其他任何东西)不存在时具有NSTimer(self.timer
),即使ARC仍按顺序将release
发送到PausibleTimer,不幸的是,NSTimer在PausibleTimer上仍有retain
。
如果第二种情况属实,则您有一个保留周期。如果第一个也是真的,那么你有一个双重保留周期。
您无法通过在PausibleTimer中实施dealloc
来解决此问题,从而使NSTimer无效,因为dealloc
不会被调用;这就是整个问题。同样,您无法通过在视图控制器中实现dealloc
来使PausibleTimer无效来解决此问题,因为(再次)dealloc
不会被调用;这是(再次)整个问题。
基本上你已经采用了NSTimer已经存在的内存管理问题并将其推回了一个阶段,其方式可能会加剧它。
我使用视图控制器拥有的普通NSTimer来解决这个问题的方法是,在视图控制器不存在之前我明确地invalidate
定时器,例如在viewWillDisappear:
。这导致NSTimer释放其目标,该目标稍后可能会以良好的顺序存在。你可能必须做那样的事情。