I have 2 classes, one of them implements a protocol that comes from an external library (so I have to use it as-is). When using Swift 6 I get an error I don't know how to solve. Here is my code. You can put it in a Swift Playground and it will show the error
import UIKit
import WebKit
final class LoginWebViewController: UIViewController {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
self.view = webView
}
func load(_ url: URL) {
let request = URLRequest(url: url)
self.webView.load(request)
}
}
protocol SomeLibProtocolIcantChange {
func loadURL()
}
final class DoSomething: SomeLibProtocolIcantChange {
let controller: LoginWebViewController
@MainActor
init() {
controller = LoginWebViewController()
}
func loadURL() {
let url = URL(string: "https://www.google.com")!
Task { @MainActor in
controller.load(url)
}
}
}
the controller.load(url)
line gives the error: Sending 'url' risks causing data races
.
I understand how in theory this could cause an issue once I start passing url
around to other places that could call modifiers on that object (when do we get an immutable URL class btw?), but this is clearly not the case as I just use it to load a webpage.
I have no idea how to solve the issue. It looks like it should be simple, but it isn't.
I tried replacing the url with a String but it gives exactly the same error.
I tried replacing the url with an Int (which makes no sense, but ok, compiler test) and it still gives the same error??
I managed to reduce it to this:
import UIKit
import WebKit
final class LoginWebViewController: UIViewController {
func load(_ someInt: Int) {
}
}
protocol SomeLibProtocolIcantChange {
func loadURL()
}
final class DoSomething: SomeLibProtocolIcantChange {
let controller: LoginWebViewController
@MainActor
init() {
controller = LoginWebViewController()
}
func loadURL() {
let someInt = 5
Task { @MainActor in
controller.load(someInt)
}
}
}
and then I get:
Sending 'someInt' risks causing data races
if I move the variable inside the task, like this:
func loadURL() {
Task { @MainActor in
let someInt = 5
controller.load(someInt)
}
}
I get: Task or actor isolated value cannot be sent
What is wrong?
If I declare the protocol as @MainActor
and remove the task it works, but the entire issue is I can't change the protocol.
This happens in Xcode Version 16.0 (16A242d)