我有一个iPad应用程序在App Store中存在了大约三个月,我收到了一些我无法弄清楚的奇怪的崩溃报告。这些不是那么频繁,自发布以来大约有15-20个实例,但仍然经常发生实际上让我感到烦恼。崩溃略有不同(请参阅下面的堆栈跟踪),但由于它们与WebCore
有关,我猜它们与应用程序中UIWebView
的使用有关,可能有一个共同的原因,虽然我不是100%肯定的。该应用程序的部署目标是iOS 6.0,但iPad 2,iPad 3和iPad Mini上的崩溃仅在iOS 7上出现。
应用程序中只有一个地方我正在使用webview,用于显示各种来源的新闻文章网页。我有一个视图控制器,它的视图有UIWebView
。此视图控制器中有一个实例存在于整个应用程序中,每次选择新文章时,现有webview将使用新选择文章的URL重新加载。
基于围绕WebCore问题的讨论建议的解决方案之一建议在控制器的delegate
方法中将webviews nil
属性设置为dealloc
。不幸的是,我不认为它适用于我的情况,因为视图控制器在应用程序的生命周期中没有被释放。
另一个问题可能是在CSS中出现错误图像引用的不正确网页(loadPendingImages崩溃)。虽然我找不到这样的页面
另外,我仔细检查并确保在主线程上进行与webview相关的操作。
崩溃是
Exception Type: EXC_BAD_ACCESS
Code: KERN_INVALID_ADDRESS
使用以下堆栈跟踪(完整的here)
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.什么修复解决了这些问题?
谢谢!
答案 0 :(得分:5)
我在一个应用程序中遇到了完全相同的问题,奇怪的是只发生在运行iOS 7的旧设备上。我怀疑这与他们无法跟上时有关。
我所拥有的是UITableView
,其中一行会打开一个UIViewController
,其上有UIWebView
个自定义广告。我发现在较旧的设备上,对象和内存的释放比我在其他平台上看到的更频繁。通过进出屏幕2到3次,我可以很容易地在iPhone 4上模仿崩溃。作为iPhone 5,我花了15分钟做同样的事情而且不能错过它。
我知道你可能觉得你的控制器没有被dealloc'd但听起来好像它或某些引用被删除了,我也看到我的代理引用在这个应用程序中也消失了几次。
我的建议以及对我有用的是停止执行webview并尽可能将所有内容设置为nil
。
在我的应用程序的一个实例中,我选择在viewWillDisappear
回调中执行此操作,因为在我的情况下它已经从用户处消失并稍后重新创建,因此我将所有内容都删除了:
[webView stopLoading];
self.webView.delegate = nil;
self.webView = nil;
答案 1 :(得分: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
来电进行此修复;)