【问题标题】:Objective-C memory issue with performSelector and infinite loop与 performSelector 和无限循环有关的 Objective-C 内存问题
【发布时间】:2015-07-10 08:42:02
【问题描述】:

我正在做一个项目,我必须尝试在给定的时间内执行给定的方法(将其视为自动模式),如果自动模式不成功,我将切换到手动模式。提醒你一下,我对 Objective-C 和 iOS 开发人员还很陌生,所以错误可能很明显。

到目前为止,这是我所做的:

-(void)viewDidLoad {  
    [self performSelector:@selector(autoMode) withObject:nil afterDelay:1.0];  
    [self performSelectorInBackground:@selector(switchManualMode) withObject:nil];  
}


-(void)autoMode {  
    @autoreleasepool {  
        while (isAutoMode == true) {  
            if ([session isRunning])  
                [self captureImage];  
                // NSLog(@"test");
       }  
    }  
}  

-(void)switchManualMode {
    [NSThread sleepForTimeInterval:2.0f];
    isAutoMode = false;
    self.button.enabled = true;

    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Changement de mode"
                                                    message:@"Du a un délai trop long, la capture automatique va être desactivée. La capture se fait maintenant de manière manuelle Touchez l'écran pour prendre une photo."
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];

    [alert show];
}

我有几个问题:
- 第一个是内存使用高峰,应用崩溃。
- 第二个是永远不会调用 switchManualMode。

我尝试只在日志中打印“test”(而不是实际调用函数“captureImage”),当我这样做时,一切都很好。

我无法发布 captureImage 的代码,但该方法会尝试从 AVCaptureSession 中获取图像,然后对其进行一些处理。
无论如何,我不明白为什么在一个案例中调用 switchManualMode 而不是在另一个案例中。

【问题讨论】:

  • 一些注意事项:为什么是@autoreleasepool?您必须指定 [alert show] 应该在主线程上执行 - 目前您正在后台线程上操作。一遍又一遍地捕获图像只会导致极高的 CPU 和内存使用率。
  • 我添加了一个@autoreleasepool,因为这是我在寻找无限循环释放内存的解决方案时发现的。当我在评论中将 captureImage 替换为 NSLog 时,[alert show] 效果很好。
  • 它不会完美运行,它不确定在什么时间点实际显示警报视图。如果它现在适合你:太好了。它不会继续。
  • 好的,我会尝试找到一种方法来“强制”它在主线程上执行。
  • 你是如何定义isAutoMode var的?

标签: ios objective-c memory infinite-loop performselector


【解决方案1】:

一个原因是您将@autoreleasepool 放在了完全错误的位置。它应该在循环。您正在同一个自动释放池中运行无限循环;这是要求内存不足的问题。以尽可能高的速率捕获图像并没有完全帮助。

另一个问题是 performSelector 将在主线程上运行,因此不会调用第二个 performSelector,因为第一个调用永远不会返回。

你应该真的,真的摆脱 performSelector 并切换到 GCD。我不想在今天编写的任何代码中看到 performSelector 和 sleep 调用。

【讨论】:

  • 我将@autoreleasepool 移动到循环内,内存继续运行。是不是 captureImage 方法中的某些元素出于某种原因留在内存中?我会研究GCD,谢谢。我知道我的第一个 performSelector 在主线程中运行,第二个在后台运行,但是当我用 NSLog 替换 captureImage 调用时,怎么会调用 switchManualMode 呢?应该每次调用还是从不调用(因为即使使用 NSLog 我也处于无限循环中)?
【解决方案2】:

我倾向于对这类事情使用递归:

-(void)buttonTappedMethod
{
    [self recusionMethod];
}

-(void)recursionMethod
{
    if(self.isAutoMode)
    {
        // ------------------------------------------------
        // Do something
        // 
        // change self.isAutoMode = YES 
        // on condition satisfied in this logic block
        // ------------------------------------------------

        // ------------------------------------------------
        // call this method again
        // ------------------------------------------------
        [self recursionMethod];
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多