I am using SwiftUI 4.0 and have the SwiftSoup package . When I try to load a website I now get this message (happens for any website)
Synchronous URL loading of https://www.cnn.com should not occur on this application's main thread as it may lead to UI unresponsiveness. Please switch to an asynchronous networking API such as URLSession.
It specifically occurs during this section of the code
if let html = try? String(contentsOf: myURL, encoding: .utf8) {
does anyone have a suggestion on how to fix this issue . This is the function I am using
import Foundation
import SwiftUI
import Combine
import SwiftSoup
func NewLinkRequest(_ LinkUrl: String) ->(LinkUrl: String ,LinkTitle: String ,LinkImage: String)
{
var newTitle = ""
let urlm = URL(string: LinkUrl)
guard let myURL = urlm else {
return ("","Failed to get url", "")
}
if let html = try? String(contentsOf: myURL, encoding: .utf8) {
do {
let doc: Document = try SwiftSoup.parseBodyFragment(html)
let headerTitle = try doc.title()
let firstImage = try doc.select("img").attr("src")
newTitle = headerTitle
return (LinkUrl,newTitle, firstImage)
} catch Exception.Error( _, let message) {
print("Message: \(message)")
} catch {
print("error")
}
return ("","", "")
} else {
return ("","Failed to get url", "")
}
}
This error happens because String(contentsOf: )
is synchronous and can cause your UI to hang. Instead, use a URLSession
like below. The following function, given a URL
, will asynchronously get you the String
.
func fetchFromURL(_ url: URL) async -> String{
let session = URLSession.shared
let (theStringAsData, _) = try await session.data(from: articleUrl)
if let returnableString = String(data: theStringAsData, encoding: .utf8)
{
return returnableAsString
} else {
return ""
}
}
let session
is the shared URLSession
for your application - docs here: URLSession.Shared
let (theStringAsData, _)
returns a Data
object and a URLResponse
- docs for this method here: https://developer.apple.com/documentation/foundation/urlsession/3767352-dataString
works, we return the new String
. Otherwise, we return an empty.import SwiftSoup
Task{
let theString = fetchFromURL(URLHERE) //Put your URL here!
//We use a do/catch block here because SwiftSoup.parse can throw
do{
let document = try SwiftSoup.parse(theString) //This is now the parsed document if it worked
print(document)
} catch { //SwiftSoup failed to parse the String into a document, so we need to handle the error
print("Failed to parse")
}
}