19

我有一个 iPad 应用程序,它在 App Store 中已经存在大约三个月了,我收到了一些我无法弄清楚的奇怪崩溃报告。这些并不是那么频繁,自发布以来大约有 15-20 个实例,但仍然频繁到足以真正让我烦恼。崩溃略有不同(请参阅下面的堆栈跟踪),但由于它们与WebCore我猜测它们与UIWebView应用程序中的使用有关,并且可能有一个共同的原因,尽管我不是 100% 肯定的。该应用程序的部署目标是 iOS 6.0,但崩溃出现在 iPad 2、iPad 3 和 iPad Mini 上,仅在 iOS 7 上。

我在应用程序中只有一个地方使用 webview,用于显示来自各种来源的新闻文章网页。我有一个视图控制器,它有一个UIWebView作为它的视图。这个视图控制器的一个实例存在于整个应用程序中,每次选择一篇新文章时,现有的 webview 都会使用新选择的文章的 url 重新加载。

基于围绕 WebCore 问题的讨论提出的解决方案之一建议在控制器的方法中设置 webviewsdelegate属性。不幸的是,我认为它不适用于我的情况,因为视图控制器在应用程序的生命周期内不会被释放。 另一个问题可能是不正确的网页在 CSS 中有错误的图像引用(loadPendingImages 崩溃)。不过,我还找不到这样的页面。 另外,我仔细检查并确保在主线程上执行与 webview 相关的操作。nildealloc

崩溃是

Exception Type: EXC_BAD_ACCESS 
Code: KERN_INVALID_ADDRESS

带有以下堆栈跟踪(此处为完整的)

0 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 815
1 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 788
2 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 948
3 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
4 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142
5 WebCore WebCore::ComputedStyleExtractor::propertyValue(WebCore::CSSPropertyID, WebCore::EUpdateLayout) const + 458

0 WebCore WebCore::StyleResolver::loadPendingImages() + 1153
1 WebCore WebCore::ResourceRequestBase::~ResourceRequestBase() + 104
2 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 782
3 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 948
4 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
5 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142

0 WebCore WebCore::StyleResolver::adjustRenderStyle(WebCore::RenderStyle*, WebCore::RenderStyle*, WebCore::Element*) + 19
1 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 964
2 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
3 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142
4 WebCore WebCore::ComputedStyleExtractor::propertyValue(WebCore::CSSPropertyID, WebCore::EUpdateLayout) const + 458
5 WebCore WebCore::CSSComputedStyleDeclaration::getPropertyValue(WebCore::CSSPropertyID) const + 42

0 WebCore WebCore::TimerBase::heapDeleteMin() + 37
1 WebCore WebCore::ThreadTimers::sharedTimerFiredInternal() + 94
2 WebCore WebCore::ThreadTimers::sharedTimerFiredInternal() + 94
3 WebCore WebCore::timerFired(__CFRunLoopTimer*, void*) + 24
4 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
5 CoreFoundation __CFRunLoopDoTimer + 782

有没有人经历过类似的崩溃?如果是这样:
1. 有没有办法复制它们?
2.如何在不复制它们的情况下调试它们?
3. 哪些修复解决了这些问题?

谢谢!

4

2 回答 2

5

我在使用的应用程序中遇到了完全相同的问题,奇怪的是它只发生在运行 iOS 7 的旧设备上。我怀疑这与他们无法跟上有关。

我所拥有的是UITableView其中一排将打开一个上面UIViewControllerUIWebView自定义广告的位置。我发现在较旧的设备上,对象和内存的释放频率比我在其他平台上看到的要频繁得多。通过进出屏幕 2 或 3 次,我可以很容易地在 iPhone 4 上模拟崩溃。作为 iPhone 5,我花了 15 分钟做同样的事情,而且无可挑剔。

我知道您可能会觉得您的控制器没有被释放,但听起来好像是或者某些引用正在被删除,我还看到我的委托引用在这个应用程序中也消失了几次。

我的建议和对我有用的是停止 webview 的执行,并尽可能地设置一切nil

在我的应用程序的一个实例中,我选择在viewWillDisappear回调中执行此操作,因为在我的情况下,它已从用户那里消失并稍后重新创建,所以我将所有内容都删除了,如下所示:

[webView stopLoading];

self.webView.delegate = nil;
self.webView = nil;
于 2013-12-23T14:41:43.060 回答
1

查看您的 Javascript-to-Objective-C 代码,如果您正在执行/调用 javascript 代码,请确保该脚本不会调用对 Objective-C 的新调用。

这是正确的用法:

Javascript >> Objective-C

Objective-C >> Javascript

这是崩溃的原因:

Objective-C >> Javascript >> Objective-C(根据某些比赛条件,这里可能会发生崩溃)

解决方案特定于您的项目代码。但最简单的方法是将所有 Javascript 包装setTimeout()在 Javascript 线程中安排执行。这是一个简单的例子,你的 Objective-C 代码需要执行这个脚本:

storeUserPhoneNumber("011 123 4567");

storeUserPhoneNumber如果函数在其主体中回调(直接或间接)Objective-C 代码,则会发生崩溃。要解决这个问题,只需将代码包装在 setTimeout 中,如下所示:

setTimeout(function() {
    storeUserPhoneNumber("011 123 4567");
}, 0);

这样做的目的是从字符串中解析 Javascript 代码,并将其放入函数中,该函数计划稍后在解析 JS 代码后的下一个事件循环滴答释放控制权返回给 Objective-C 时执行。

Objective-C >> Javascript请记住,您需要对所有呼叫进行此修复;)

于 2015-09-04T14:01:50.090 回答