iOS程序,在Web页面点击后返回原生页面时崩溃了:
通过Xcode调试如下:
崩溃日志是:
“url:{“url”:”http:/xx.xx.xx.xx//skrDev/src/report/invoice.html?t=1510207894395&drAreaFiltrateCode=SKR02-01-04&drAreaFiltrateName=”,”tabId”:”invoice”;} ================================================================= Main Thread Checker: UI API called on a background thread: -[UIApplication delegate] PID: 5713, TID: 782314, Thread name: WebThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 21 Backtrace: 4 SRTDev 0x0000000103b8f66c _T06SRTDev27ReportDetailsViewControllerCACSS3url_SS5titletcfc + 300 5 SRTDev 0x0000000103b8e73f _T06SRTDev27ReportDetailsViewControllerCACSS3url_SS5titletcfC + 79 6 SRTDev 0x00000001038ad239 _T06SRTDev7AppHostC8intentToySSF + 2761 7 SRTDev 0x00000001038adfba _T06SRTDev7AppHostC8intentToySSFTo + 74 8 CoreFoundation 0x000000010872432c __invoking___ + 140 9 CoreFoundation 0x0000000108724200 -[NSInvocation invoke] + 320 10 JavaScriptCore 0x0000000104b5fe18 … 33 WebCore 0x000000011441bb73 -[WAKWindow sendEventSynchronously:] + 259 34 UIKit 0x0000000105bb31bc _ ================================================================= Main Thread Checker: UI API called on a background thread: -[UIView init] PID: 5713, TID: 782314, Thread name: WebThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 21 Backtrace: 4 SRTDev 0x00000001038b16a3 _T0So9UIWebViewCABycfcTO + 19 5 SRTDev 0x00000001038aeb6c _T0So9UIWebViewCABycfC + 60 … 14 libsystem_pthread.dylib 0x000000010bca2887 _pthread_body + 0 15 libsystem_pthread.dylib 0x000000010bca208d thread_start + 13 ) StatusBarHeight:20.0,NaviBarHeight:32.0,StatusNaviHeight:52.0 StatusBarHeight:20.0,NaviBarHeight:32.0,StatusNaviHeight:52.0 … |
本来以为是其他逻辑方面的错误呢。
但是又看到了:
This application is modifying the autolayout
之类的错误
-》感觉是:
解决了这个问题,估计就不会崩溃了。
而之前之所以没有崩溃,是因为之前要求不严格,现在新的iOS11+XCode9,要求严格,所以会崩溃。
去找找是哪里的 background线程中修改了UI元素
其实Xcode9中,已经可以帮我们找到是哪里出现这类问题了:
然后点击进去找找
找到了,此处的:
AppHost的intentTo
是H5页面调用iOS 原生的入口
其中intentTo中,调用了VC:ReportDetailsViewController
而ReportDetailsViewController的init中,是有些UI元素的初始化的,比如:UIWebView
所以,要确保H5调用原生的intentTo中的ReportDetailsViewController,是处于Main Thread主线程才行。
而之前的代码:
func intentTo(_ jsonString: String) { 。。。 // current use the url inside dict to jump if let url = dict?[“url”]{ 。。。 let ReportDetailsVC = ReportDetailsViewController(url: url as! String,title:titleC) controller?.show(ReportDetailsVC, sender: self) }else{ 。。。 let ReportDetailsVC = ReportDetailsViewController(url: jsonString,title:titleC) controller?.show(ReportDetailsVC, sender: self) } } } |
没有注意这点。
所以相关代码改为:
dispatchMain_sync { let reportDetailsVC = ReportDetailsViewController(url: url as! String, title:titleC) self.controller?.show(reportDetailsVC, sender: self) } dispatchMain_sync { let reportDetailsVC = ReportDetailsViewController(url: jsonString, title:titleC) self.controller?.show(reportDetailsVC, sender: self) } |
即可。
其中dispatchMain_sync是我自己整理的函数:
// // CrifanThread.swift // Crifan Li // Updated: 2017/09/28 // import UIKit let MainThread:DispatchQueue = DispatchQueue.main let UserInteractiveThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive) let UserInitiatedThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated) let DefaultThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default) let UtilityThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.utility) let BackgroundThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background) let UnspecifiedThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.unspecified) /*************************************************************************** * GCD/Queue/Thread functions ***************************************************************************/ func delayDispatch(_ delayTimeInSec:Double, inThread:DispatchQueue, thingsTodo:@escaping ()->()) { let dispatchDelayTime = DispatchTime.now() + Double(Int64(delayTimeInSec * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) inThread.asyncAfter(deadline: dispatchDelayTime, execute: thingsTodo) } func delayDispatchInMainThread(_ delayTimeInSec:Double, thingsTodo:@escaping ()->()) { delayDispatch(delayTimeInSec, inThread: MainThread, thingsTodo: thingsTodo) } func dispatchMain_sync(_ delayTimeInSec:Double = 0.0, thingsTodo:@escaping ()->()) { delayDispatchInMainThread(delayTimeInSec, thingsTodo: thingsTodo) } func delayDispatchInBackgroundThread(_ delayTimeInSec:Double, thingsTodo:@escaping ()->()) { delayDispatch(delayTimeInSec, inThread: BackgroundThread, thingsTodo: thingsTodo) } func dispatchBackground_async(_ thingsTodo:@escaping ()->()) { BackgroundThread.async(execute: thingsTodo) } func dispatchUserInitiated_async(_ thingsTodo:@escaping ()->()) { UserInitiatedThread.async(execute: thingsTodo) } func dispatchMain_async(_ thingsTodo:@escaping ()->()) { MainThread.async(execute: thingsTodo) } |
更多代码详见:
https://github.com/crifan/crifanLib/blob/master/swift/Thread/CrifanThread.swift
【总结】
此处H5页面调用iOS原生导致页面崩溃,其实不是互调的问题,而是:
老生常谈的,在后台非UI线程操作UI元素而导致崩溃的。
-》如果你发现之前同样代码为何没有奔溃,那么是因为iOS11(Xcode9)之前要求不严格
-》iOS11(Xcode9)之后要求严格,所以就报错了。且Xcode9可以监测出运行时的这类问题:
在Running AppName on iPhone x 的后面,有个 淡紫色背景的数字,比如3
表示有几个这类问题,点击查看,即可找到对应代码,从而定位错误原因,解决问题了。
转载请注明:在路上 » 【已解决】iOS中WebView回调原生页面时崩溃