0

我想从一开始就解释我的问题。我正在使用 UIWebView 创建一个应用程序。此外,我正在用户使用该应用程序的那一刻捕获屏幕,并使用该图像阵列创建一个视频。

我正在使用 NSTimer 来获取屏幕截图。我工作得很好,但我遇到了一个问题。那是当用户开始滚动网页或当用户在屏幕上按住触摸时 NSTimer 暂停并且在他释放触摸后 NSTimer 继续。

这是我用来获取屏幕截图的 NSTimer。

assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                    target:self
                                                  selector:@selector (writeSample)
                                                  userInfo:nil
                                                   repeats:YES];

我用谷歌搜索了这个问题,大多数人都遇到了和我一样的问题。所以他们找到了答案,那就是使用 NSRunLoop。他们说它停止暂停 NSTimer。

所以我使用 NSRunLoop 并将 NSTimer 添加到 NSRunLoop 中,这是我这样做之后的代码。

NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                    target:self
                                                  selector:@selector (writeSample)
                                                  userInfo:nil
                                                   repeats:YES];

[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];

这段代码运行良好,它没有停止暂停 NSTimer。但是在我使用 NSRunLoop 之后,我的应用程序变得非常慢。将网页加载到 WebView 中也需要花费大量时间,并且滚动速度也很慢。

于是我又开始在谷歌搜索,我发现了这个问题。那就是所有这些事情都在主线程中进行,而 iphone 无法同时处理所有事情。所以人们建议使用 NSThread 来解决这个问题。所以我所做的是创建一个 NSThread 并将进程附加到自定义线程。

这是我将 NSThread 应用到它之后的代码。

    [NSThread detachNewThreadSelector:@selector(launchTimer) toTarget:self withObject:nil];

 -(void)launchTimer{


    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                        target:self
                                                      selector:@selector (writeSample)
                                                      userInfo:nil
                                                       repeats:YES];
 
    [runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
    [runLoop run];

 }


-(void) writeSample{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //did some coding here to take screen shot
    [pool release];
}

这解决了永远放慢应用程序的问题,我的应用程序再次运行非常顺利,但现在带来了严重的问题。我猜这是因为使用线程而发生的。我的自定义线程和主线程现在发生冲突并导致应用程序崩溃。我搜索了谷歌的原因。我发现了一些与此类问题相关的问题,有些人回答了这些问题并说任何 UI 更改都需要在主线程中完成。UIWebView WebThread 也必须在主线程中运行。

这些是我收到的一些错误报告,

在此处输入图像描述

在此处输入图像描述

这些错误就像一些线程冲突。但我不知道如何解决这个问题。我将我的代码用于一些没有任何 Web 视图或地图的本机应用程序。所以它在没有崩溃的情况下运行良好。但是当我将它用于具有 WebView 或 Map 的应用程序时,它有时会崩溃并给我这个错误。

我在这里遇到了很多麻烦,如果有人可以给出任何想法或示例代码来处理线程,处理线程优先级,或者在不使用 NSThreads 的情况下使用 NSTimer 和 NSRunLoop,或者在不使用 NSThread 的情况下克服应用程序缓慢,任何答案都是非常非常非常有帮助,我期待很快收到您的来信。

谢谢。

4

2 回答 2

0

我的猜测是您为捕获屏幕截图而编写的代码导致了问题。一个简单的测试是注释掉 writeSample 方法中的所有代码,看看应用程序是否仍然崩溃。我这样说是因为你是对的,所有与 UI 相关的任务都应该始终在主线程中工作。

我建议为计时器使用单独的线程,这样您的计时器就不会暂停,然后从 writeSample 方法强制屏幕捕获代码在主线程上运行。

希望这可以帮助

于 2012-12-12T11:17:44.303 回答
0

首先:

一旦你使用了定时器,你就在使用运行循环——你可以从参考中很容易地看到

计时器与运行循环一起工作。

(这是第二段的第一句话)

有了这个,你的症状:

  • 通过捕获图像阻塞线程会导致它结结巴巴。

这不应该让你感到惊讶!

  • 将工作从该线程上移开,释放第一个线程的压力。

震惊,我知道!

好吧,鉴于您没有向我们展示任何导致同步问题的代码,(阅读:崩溃)这个讽刺的答案是我可以为您提供的所有帮助。

那以及阅读和内化我上面链接到的文档的技巧……</p>


编辑

我只是忘了提,这个:

NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:blablabla];
[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];

没有多大意义,因为……</p>

-scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:

创建并返回一个新的 NSTimer 对象,并以默认模式将其安排在当前运行循环中。

(这在宏伟的文档中也有解释。)

本质上:当您在自己的私有线程上时,默认模式就足够了。不过,您必须确保运行循环实际上正在运行。

这实际上是由该代码片段的最后一行完成的,但它实际上会导致您的方法在定时器被取消之前不会返回......</p>

于 2012-12-13T13:14:50.230 回答