Tengo una aplicación que puede descargar archivos desde una vista web. Funcionaba bien en iOS 12 pero no funciona. Estoy recibiendo el error

Las modificaciones al motor de diseño no deben realizarse desde un subproceso en segundo plano después de que se haya accedido desde el subproceso principal.

Y

Esta aplicación está modificando el motor de distribución automática desde un subproceso en segundo plano después de acceder al motor desde el subproceso principal. Esto puede conducir a la corrupción del motor y accidentes extraños.

Este es mi código 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;
}

}

Encontré esta publicación (Las modificaciones al motor de diseño no se deben realizar desde un hilo en segundo plano después de que se haya accedido desde el hilo principal) pero soy un principiante y no estoy seguro de cómo implementar esto.

1
Nathan Marchant 1 oct. 2019 a las 11:30

1 respuesta

La mejor respuesta

Debe ejecutar cualquier código que acceda a la interfaz de usuario en el hilo principal.

Como las tareas URLSession se ejecutan en un hilo en segundo plano, debe agregar un bloque 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")
    })
}

Nota:

El parámetro en el cierre UIAlertAction debe ser una instancia, no un tipo. Si el parámetro no se usa, puede reemplazarlo con un carácter de subrayado (por ejemplo, handler:{ _ in)

1
vadian 1 oct. 2019 a las 08:41