我写了一个actor,允许我在线下载和解析一些数据,该函数下载数据并将结果附加到通道数组中。
actor BackgroundParser : ObservableObject {
@Published var channels : [String: [PlaylistItem]] = [:]
let parser = PlaylistParser()
func fetchOnMemory(lista: PlayListModel,url: String ,_ completion: @escaping (_ isdownloading:Bool) -> Void) async {
guard let m3uURL = URL(string: url) else {return}
completion(true)
var counter = 0
AF.request(m3uURL).responseString { response in
switch response.result {
case .success(let m3uContent):
do{
let playlist = try self.parser.parse(m3uContent)
let media = playlist.medias
print("QUESTA LISTA CONTIENE \(media.count)")
for item in media {
let duration = item.duration
let attributes = item.attributes
let tvgId = attributes.id
let tvgName = attributes.name
let tgvcountry = attributes.country
let tvglanguage = attributes.language
let tvgLogo = attributes.logo
let tvgchno = attributes.channelNumber
let tvgShift = attributes.shift
let groupTitle = attributes.groupTitle
let seasonNumber = attributes.seasonNumber
let episodeNumber = attributes.episodeNumber
let kind = item.kind.rawValue
let url = item.url
let def : String = "XXX"
print("\(counter) of \(media.count)-- id: \(tvgId ?? def) -- name: \(tvgName ?? def) -Title: \(groupTitle ?? def)")
let playlistItem = PlaylistItem(duration: duration, tvgId: tvgId, tvgName: tvgName, tvgcountry: tgvcountry, tvglanguage: tvglanguage, tvgLogo: tvgLogo, tvgchno: tvgchno, tvgshift: tvgShift, groupTitle: groupTitle ?? "NOT CLASSIFIED", seasonNumber: seasonNumber, episodeNumber: episodeNumber, kind: kind, url: url)
self.updateChannelList(with: playlistItem)
// print("parse-------\(counter)--\(String(describing: tvgName))")
counter += 1
}
completion(false)
} catch {
completion(true)
print("FAIL CATCH")
}
case .failure(let error):
completion(true)
print("Failed to fetch m3u content: \(error)")
}
}
}
func updateChannelList(with playlistItem: PlaylistItem) {
// Assuming listofChannel is a class-level or instance-level variable
// and you want to modify it in-place
// Check if the groupTitle already exists in the dictionary
if var existingPlaylist = channels[playlistItem.groupTitle] {
// If it exists, append the new playlist item
existingPlaylist.append(playlistItem)
channels[playlistItem.groupTitle] = existingPlaylist
} else {
// If it doesn't exist, create a new key with an array containing the playlist item
channels[playlistItem.groupTitle] = [playlistItem]
}
}
}
我现在尝试在视图中显示数据,但收到错误“无法从主要参与者引用参与者隔离属性“通道””。
struct ListViewDetails: View {
@State var isLoading = true
@StateObject var parser = BackgroundParser()
let columns = [
GridItem(.fixed(300)),GridItem(.fixed(300)),GridItem(.fixed(300)),GridItem(.fixed(300)),GridItem(.fixed(300)),GridItem(.fixed(300)),
]
var body: some View {
if isLoading {
ProgressView("Fetching Data...")
.progressViewStyle(CircularProgressViewStyle())
}
ScrollView(.vertical){
LazyVGrid(columns: columns,alignment: .center,spacing: 20) {
ForEach(parser.channels.sorted(by: { $0.key < $1.key }), id: \.key) { group , channels in
DetailsChannelGroup(group: group, channels: channels)
}
}
}
.task {
await parser.fetchOnMemory(lista: item, url: item.playlistUrl) { isdownloading in
isLoading = isdownloading
}
}
}
}
每个循环都会出现错误,因为我尝试访问已发布的数组。
我怎样才能得到这些数据?
您将太多概念混合在一起:完成、异步等待、组合。我可以重构上面的代码,仅在您使用 Alamofire 时才使用
@Published
,并绕过一个步骤:将 AF 完成包装为异步等待。 SwiftUI 中的 View
的作用类似于 ViewModel,因此我们只需要在这里进行数据绑定。 @Published
当 View 的值发生变化时,会大声喊出重新渲染 View,并且还会在此处删除完成。
final class BackgroundParser: ObservableObject {
@Published var isLoading = false
@Published var channels: [String: [PlaylistItem]] = [:]
func fetchOnMemory(lista: PlayListModel,url: String) {
isLoading = true
//fetch and sort channels here
isLoading = false
}
}
@StateObject private var parser = BackgroundParser()
var body: some View {
...
.onAppear {
parser.fetchOnMemory()
}
}
输出应该类似于: