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", "")
}
}
CodePudding user response:
The Problem
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
.
The Solution
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 ""
}
}
Code breakdown:
let session
is the sharedURL Session
for your application - docs here: URLSession.Sharedlet (theStringAsData, _)
returns aData
object and aURLResponse
- docs for this method here: https://developer.apple.com/documentation/foundation/urlsession/3767352-data- We check to ensure this data is not nil, and if the typecast to
String
works, we return the newString
. Otherwise, we return an empty.
Example Usage:
import SwiftSoup
Task{
let theString = fetchFromURL(URLHERE) //Put your URL here!
do{
let document = try SwiftSoup.parse(theString) //This is now the parsed document if it worked
print(document)
} catch {
print("Failed to parse")
}
}