У меня есть класс API, в котором я создаю задачу данных сеанса URL-адреса, которая обновляет значение свойстваbirdResult в классе, когда задача завершается из блока DispatchQueue.main.async.
В Swift 6 появляется следующая ошибка:
Мой код класса выглядит так:
class BirdsAPI: ObservableObject {
static let url = URL(string: "https://api.inaturalist.org/v1/observations?iconic_taxa=Aves&per_page=50&order=desc&order_by=created_at")
@Published var birdResults: [BirdResult] = []
func fetchObservations() {
URLSession.shared.dataTask(with: URLRequest(url: BirdsAPI.url!)) { data, response, error in
guard error == nil else { return }
let decoder = JSONDecoder()
do {
let body = try decoder.decode(Body.self, from: data!)
DispatchQueue.main.async {
self.birdResults = body.results
}
} catch let error {
print("error decoding data, \(error)")
}
}.resume()
}
}
Почему это и как я могу это исправить?
@Senable описывает типы, которыми можно безопасно делиться одновременно. то есть:
struct A: Senable { } //✅
class B: Senable { } //❌ unsynchronized
final class C: Senable { //❌ mutating property
var birdResults: [BirdResult] = []
}
final class D: Senable { //✅
let birdResults: [BirdResult]
}
Цель состоит в том, чтобы избежать риска возникновения гонок за данными. В вашем примере ваш класс BirdsAPI
не соответствует Senable
, но завершениеHandler отмечено @Sendable
:
функция dataTask( с запросом: URLRequest, завершениеHandler: @escaping @Sendable (Данные?, URLResponse?, (любая ошибка)?) -> Void ) -> URLSessionDataTask
Хотя вы можете игнорировать ошибку Swift 6, используя @unchecked
. Не следует этого делать, если у вас нет внутреннего механизма блокировки при изменении свойства.
class BirdsAPI: ObservableObject, @unchecked Sendable { } //<- here
Таким образом, я рекомендую выполнить рефакторинг кода следующим образом и избегать объединения семейства DispatchQueue
с новым параллелизмом async await
.
@MainActor
func fetchObservations() async throws {
let (data, response) = try await URLSession.shared.data(for: URLRequest(url: BirdsAPI.url!))
let decoder = JSONDecoder()
let body = try decoder.decode(Body.self, from: data!)
self.birdResults = body.results
}