我有一个可以从webview下载文件的应用程序。它在ios 12中工作正常,但不工作。我遇到了错误

从主线程访问布局引擎后,不得从后台线程对其进行修改。



从主线程访问引擎后,此应用程序正在从后台线程修改自动布局引擎。这会导致引擎损坏和奇怪的崩溃。

这是我的view.controller代码:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
    print(request.url as Any)
    if request.url!.absoluteString.range(of: "/download/") != nil {
        let extention = request.url!.absoluteString.slice(from: "&fileextension=", to: "&")?.lowercased()
        var name = request.url!.absoluteString.slice(from: "&name=", to: "&")?.lowercased()
        name =  name?.replacingOccurrences(of: "+", with: " ")
        DownlondFromUrl(request.url! as URL,name!, extention!)
        return false
    }
    return true
}
func DownlondFromUrl(_ url: URL,_ name:String,_ extensionfile:String){
    // Create destination URL
    let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
    let destinationUrl = documentsUrl!.appendingPathComponent(name + ".\(extensionfile)")

    //Create URL to the source file you want to download
    let fileURL = url

    let sessionConfig = URLSessionConfiguration.default
    let session = URLSession(configuration: sessionConfig)

    let request = URLRequest(url:fileURL)

    let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
        if let tempLocalUrl = tempLocalUrl, error == nil {
            let dataFromURL = NSData(contentsOf: tempLocalUrl)
            dataFromURL?.write(to: destinationUrl, atomically: true)

            let alert = UIAlertController.init(title: "Download", message: "File download Successful. Do you want open file ", preferredStyle: .actionSheet)
            alert.addAction(UIAlertAction(title: "Open", style: .default , handler:{ (UIAlertAction)in
                let fileBrowser = FileBrowser()
                self.present(fileBrowser, animated: true, completion: nil)
            }))
            alert.addAction(UIAlertAction(title: "Share", style: .default , handler:{ (UIAlertAction)in

                let activityViewController = UIActivityViewController(activityItems: [destinationUrl], applicationActivities: nil)
                activityViewController.popoverPresentationController?.sourceView = self.view
                self.present(activityViewController, animated: true, completion: nil)
            }))
            alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler:{ (UIAlertAction)in
            }))

            self.present(alert, animated: true, completion: {
                print("completion block")
            })
        } else {
            print("Error took place while downloading a file. Error description: %@", error?.localizedDescription as Any);
        }
    }
    task.resume()
}
override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.isNavigationBarHidden = true;
}

}

我已经找到了这篇文章(Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread),但是我非常新手,不知道如何实现。

最佳答案

您必须运行访问主线程上的UI的任何代码。

URLSession任务在后台线程上运行时,您必须添加DispatchQueue

DispatchQueue.main.async {
    let alert = UIAlertController.init(title: "Download", message: "File download Successful. Do you want open file ", preferredStyle: .actionSheet)
    alert.addAction(UIAlertAction(title: "Open", style: .default , handler:{ action in
        let fileBrowser = FileBrowser()
        self.present(fileBrowser, animated: true, completion: nil)
    }))
    alert.addAction(UIAlertAction(title: "Share", style: .default , handler:{ action in

        let activityViewController = UIActivityViewController(activityItems: [destinationUrl], applicationActivities: nil)
        activityViewController.popoverPresentationController?.sourceView = self.view
        self.present(activityViewController, animated: true, completion: nil)
    }))
    alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel)

    self.present(alert, animated: true, completion: {
        print("completion block")
    })
}

注意:
UIAlertAction闭包中的参数必须是实例而不是类型。如果未使用该参数,则可以将其替换为下划线字符(例如handler:{ _ in)

10-08 05:27