【问题标题】:A label is getting deallocated due to memory leak ,what shall i do?由于内存泄漏,标签正在被释放,我该怎么办?
【发布时间】:2023-04-08 23:18:01
【问题描述】:

代码:因此,当计时器 id 停止并重新启动几次时,此代码运行良好,但是当我们重复相同的次数超过 30 次时会崩溃。

   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
aTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(ShowTime:) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] run];});

更新标签

-(void)ShowTime:(NSTimer *) timer{

NSTimeInterval now = [[NSDate date] timeIntervalSince1970];

double Timeinterval= (now - StartClickTime)/60  ;

double wait=([FrequencyPerHour doubleValue]+[PromptTime doubleValue]+2.75);
double warningTime=([FrequencyPerHour doubleValue]+[WarningTime doubleValue]);
if (WarninigBeep == NO) {


    if ((Timeinterval*60) >= warningTime)
    {
        // NSString *path = [NSString stringWithFormat:@"%@/rapidbeep9.mp3", [[NSBundle mainBundle] resourcePath]];
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"rapidbeep9"
                                                             ofType:@"mp3"
                                                        inDirectory:nil];

        NSURL *soundUrl = [NSURL fileURLWithPath:filePath];
        // Create audio player object and initialize with URL to sound
        _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
        [_audioPlayer play];
        WarninigBeep=YES;


    }
}
[lbltimerDisplay setText:[NSString stringWithFormat:@"%.4f", Timeinterval]];}

【问题讨论】:

  • [CFString 长度]:消息发送到已释放的实例 - 出现此错误
  • 添加您的代码以便我们检查。
  • 我正在使用这个代码 -(void)viewDidDisappear:(BOOL)animated{ [aTimer invalidate]; aTimer = nil; [超级 viewDidDisappear:YES]; }
  • 基本上应用程序从数据库中获取之前停止的记录并在'showtimer'中进行计算并在标签上显示结果

标签: objective-c xcode memory-management memory-leaks


【解决方案1】:

这里有几个问题:

  • 您正在后台线程上运行计时器,但您正在更新 UI,这应该始终在主线程上进行。如果您要在后台线程上运行它,请确保将 UI 更新分派回主线程:

    dispatch_async(dispatch_get_main_queue(), ^{
        self.timerLabel.text = [NSString stringWithFormat:@"%.4f", Timeinterval];
    });
    
  • 您正在这个后台线程上启动一个运行循环,但永远不要停止它。如果您查看documentation 中的run,它会警告您:

    如果您希望运行循环终止,则不应使用此方法。相反,请使用其他运行方法之一,并在循环中检查您自己的其他任意条件。一个简单的例子是:

    BOOL shouldKeepRunning = YES;        // global
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    

    如果您不停止运行循环并重复此过程太多次,您将消耗所有非常有限的全局队列工作线程,使用所有这些废弃的运行循环减慢应用程序,并耗尽您的记忆。

  • 更简单的是,如果您希望计时器在后台线程上运行,则根本不要使用NSTimer/NSRunLoop,而是使用可以在后台队列上运行而无需运行的 GCD 计时器环形。因此,为计时器声明一个属性:

    @property (nonatomic, strong) dispatch_source_t timer;
    

    然后像这样启动和停止计时器:

    - (void)startTimer {
        dispatch_queue_t queue = dispatch_queue_create("com.domain.app.timer.16782529", 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        if (self.timer) {
            dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), 0.1 * NSEC_PER_SEC, 0);
    
            dispatch_source_set_event_handler(self.timer, ^{
                // do/call whatever you want here
            });
    
            dispatch_resume(self.timer);
        }
    }
    
    - (void)cancelTimer {
        dispatch_source_cancel(self.timer);
    }
    
  • 我认为你现在不应该解决这个问题,但如果我想要不断更新显示经过的时间,然后每秒播放一次声音,我会:

    • 使用显示链接显示经过的时间。它就像一个计时器,但针对屏幕更新进行了优化。如果您要更新屏幕上的内容,这将提供最佳的用户体验。

    • 要播放声音(每秒一次?),我只需要使用标准计时器。而且我不会倾向于每次都创建一个新的AVAudioPlayer,而是这样做一次,然后以任何有意义的频率播放音频。

说了这么多,我隐约怀疑这里可能还有其他更深层次的问题,但似乎你应该先修复这些计时器/运行循环问题,然后看看其他问题是否仍然存在。

这个问题的标题假定由于内存压力而释放了某些东西。这不是记忆压力的表现方式。更可能的问题是视图控制器已被释放,而该后台进程仍在触发。我建议在解除分配的例程中添加NSLog 语句,并查看在解除分配之前或之后是否发生崩溃(如果它仍然发生已解决上述问题)。

无论如何,如果它仍然崩溃,请查看堆栈跟踪(或添加异常断点),以便您可以准确找到崩溃的位置。如果不知道问题出在哪里,就很难诊断。

【讨论】:

  • 非常感谢@rob 它的工作......你明白我的意思......
猜你喜欢
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 2011-01-27
  • 2019-07-13
  • 1970-01-01
  • 2011-08-09
相关资源
最近更新 更多