Думаю, я делаю вещи по книге. Однако я продолжаю сталкиваться с предупреждениями/ошибками компилятора.
Вот затронутый код, который находится в замыкании View.onChange(of:_:), где currentMediaTitle — это просто String, а player — это просто AVPlayer:
currentMediaTitle = ""
Task {
guard let asset = player.currentItem?.asset else {
currentMediaTitle = nil
return
}
let allMetadata = try await asset.load(.metadata) // WARNING: Non-sendable type '[AVMetadataItem]' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary
guard let titleMetadata = allMetadata.first(where: { item in
item.identifier == AVMetadataIdentifier.commonIdentifierTitle
})
else {
currentMediaTitle = nil
return
}
let titleValue = try await titleMetadata.load(.value) // WARNING: Passing argument of non-sendable type 'AVMetadataItem' outside of main actor-isolated context may introduce data races
let title = (titleValue as? NSString) as String?
self.currentMediaTitle = title
}
вот версия скриншота, если вам так удобнее:
Итак, есть несколько вещей, которые... кажутся мне парадоксальными:
actor, хотя они оба classAVMetadataItem, но вызываю для него метод. Возможно, я могу понять, как он так думает, потому что Swift, похоже, рассматривает методы как статические функции, которые принимают self в качестве первого аргумента, но даже в этом случае я не понимаю, как это может нарушить структурированный параллелизм, поскольку он самоограничен.Я даже попробовал несколько вещей, чтобы все это произошло на MainActor, но он все равно выдавал мне те же самые предупреждения, так что... Я как бы застрял здесь.
Что мне делать, чтобы устранить эти предупреждения?
У меня такое ощущение, что мы получим ответы на эти вопросы завтра на WWDC, когда будут говорить о Swift 6 и Xcode 16.
@Sweeper, я попробую, спасибо. Это в View-х .onChange(of:_:). Я согласен, что он должен работать в фоновом режиме, но в предупреждении прямо говорится, что это проблема: «Передача аргумента неотправляемого типа AVMetadataItem вне основного контекста, изолированного от актера, может привести к гонкам данных»
@dalton_c Я на это надеюсь, но боюсь, что это будет несколько месяцев критических ошибок, отзывов, которые попадут в Void Hole, противодействия со стороны сопровождающих Swift, прежде чем они поймут варианты использования, и ворчащих боджей / клуджей.
@Sweeper Task.detached кажется, это то, что мне нужно. Спасибо! Пожалуйста, напишите это в качестве ответа, чтобы я мог принять его :3





Код в Task { ... } изолирован от главного актера, а load — нет, поэтому неотправляемые типы, такие как AVMetadataItem, не могут передаваться между ними, пересекая границы актеров.
Вы можете использовать Task.detached для запуска кода главного актера, но при этом все равно будет захватываться self (при условии, что currentMediaTitle является членом self), который, вероятно, не подлежит отправке. Вы по-прежнему получите предупреждение, если включите строгую проверку параллелизма.
Кажется, вы извлекаете заголовок какого-то AVAsset, поэтому я бы написал это как расширение AVAsset:
extension AVAsset {
func mediaTitle() async throws -> String? {
let allMetadata = try await load(.metadata)
guard let titleMetadata = allMetadata.first(where: { item in
item.identifier == AVMetadataIdentifier.commonIdentifierTitle
})
else {
return nil
}
let titleValue = try await titleMetadata.load(.value)
let title = (titleValue as? NSString) as String?
return title
}
}
и теперь вы можете сделать:
Task {
currentMediaTitle = try await player.currentItem?.asset.mediaTitle()
}
Это снова отправляет AVAsset через границы актеров, и вы получите предупреждение, если включите строгую проверку параллелизма. Вы можете отключить это предупреждение, используя @preconcurrency import AVFoundation, и это, вероятно, не будет проблемой после того, как будет реализована изоляция субъектов на основе региона.
Сможешь
Task.detached? Где бы ни находился этот код, он находится в изолированном от основного актера контексте, и я не думаю, что его следует запускать на главном актере.