LazyView中带有SwiftUI的LPLinkView将使CPU保持在100%

LazyView中带有SwiftUI的LPLinkView将使CPU保持在100%,swiftui,combine,Swiftui,Combine,如果在SwiftUI惰性视图(如LazyVStack、LazyHStack或LazyVGrid)中使用LPLinkView(包装在UIViewRepresentable中),则在链接完成获取后,cpu将保持100% 在提供的示例中,运行应用程序时不做任何更改。您将看到,在获取链接时,CPU会出现峰值,然后在加载所有链接后,CPU就会稳定下来 再次尝试运行应用程序,但将保存链接视图的VStack更改为LazyVStack。您将看到,即使在所有链接都完成抓取之后,cpu仍保持在100% 我相信这只是

如果在SwiftUI惰性视图(如LazyVStack、LazyHStack或LazyVGrid)中使用LPLinkView(包装在UIViewRepresentable中),则在链接完成获取后,cpu将保持100%

在提供的示例中,运行应用程序时不做任何更改。您将看到,在获取链接时,CPU会出现峰值,然后在加载所有链接后,CPU就会稳定下来

再次尝试运行应用程序,但将保存链接视图的VStack更改为LazyVStack。您将看到,即使在所有链接都完成抓取之后,cpu仍保持在100%

我相信这只是一个迅捷的错误。我已提交反馈(FB8879936)

导入快捷界面
导入链接演示文稿
进口联合收割机
结构PicSum:可解码、可识别{
变量id:String
var下载url:String
}
类ContentModel:ObservableObject{
@已发布的变量链接=[RichLink]()
@发布的var isLoading=false
var subscriptions=Set()
让picSumURL=URL(字符串:https://picsum.photos/v2/list?page=2&limit=10")!
func fetchLinks(){
links.removeAll()
isLoading=true
返回URLSession.shared.dataTaskPublisher(用于:picSumURL)
.map(\.data)
.decode(类型:[PicSum].self,解码器:JSONDecoder())
.flatMap{picSumArray in
出版商。合并很多(
微光阵列
.map{URL(字符串:$0.download_URL)!}
.map(self.fetchLink)
)
}
.map{RichLink(for:$0)}
.collect()
.receive(在:DispatchQueue.main上)
.删除任何发布者()
.sink(接收完成:{uu}in
打印(“已完成加载所有链接”)
self.isload=false
},receiveValue:{中的链接
self.links=链接
}).store(位于:&订阅中)
}
private func fetchLink(用于url:url)->AnyPublisher{
让metadataProvider=LPMetadataProvider()
回报未来{承诺未来}
DispatchQueue.main.async{
metadataProvider.startFetchingMetadata(for:url){(元数据,错误)位于
如果让元数据=元数据{
承诺(结果、成功(元数据))
}否则,如果let error=error{
承诺(结果、失败(错误))
}否则{
法塔莱罗()
}
}
}
}.删除任何发布者()
}
}
结构ContentView:View{
@StateObject变量模型=ContentModel()
var body:一些观点{
导航视图{
滚动视图{
//更改为惰性视图(LazyVStack、LazyHStack或LazyVGrid)会导致
//即使在获取所有链接后,CPU仍将保持在100%
VStack(间距:20){
ForEach(model.links){linkin
LinkView(richLink:link)
}
}
}
.overlay(ProgressView().opacity(model.isLoading?1:0).scaleEffect(2.5))
.navigationTitle(“丰富链接”)
.工具栏{
工具栏项(位置:。导航栏栏栏){
按钮(“提取”){
model.fetchLinks()
}.disabled(型号为isLoading)
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
类RichLink:NSObject,可识别{
变量id:Int!
var元数据:LPLinkMetadata!
init(用于元数据:LPLinkMetadata){
super.init()
id=Int(日期.时间间隔IncerenceDate)
self.metadata=元数据
}
}
结构链接视图:UIViewRepresentable{
var richLink:richLink
func makeUIView(上下文:context)->LPLinkView{
guard let metadata=richLink.metadata else{
返回LPLinkView()
}
让linkView=LPLinkView(元数据:元数据)
返回链接视图
}
func updateUIView(uiView:LPLinkView,context:context){
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView()
}
}
import SwiftUI
import LinkPresentation
import Combine

struct PicSum: Decodable, Identifiable{
    var id: String
    var download_url: String
}

class ContentModel: ObservableObject{
    @Published var links = [RichLink]()
    @Published var isLoading = false
    var subscriptions = Set<AnyCancellable>()
    let picSumURL = URL(string: "https://picsum.photos/v2/list?page=2&limit=10")!
    
    func fetchLinks(){
        links.removeAll()
        isLoading = true
        
        return URLSession.shared.dataTaskPublisher(for: picSumURL)
            .map(\.data)
            .decode(type: [PicSum].self, decoder: JSONDecoder())
            .flatMap { picSumArray in
                Publishers.MergeMany(
                    picSumArray
                        .map{URL(string: $0.download_url)!}
                        .map(self.fetchLink)
                )
            }
            .map{RichLink(for: $0)}
            .collect()
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
            .sink(receiveCompletion: {_ in
                print("Finished loading all links.")
                self.isLoading = false
            }, receiveValue: {links in
                self.links = links
            }).store(in: &subscriptions)
    }
    
    private func fetchLink(for url: URL) -> AnyPublisher <LPLinkMetadata, Error> {
        let metadataProvider = LPMetadataProvider()
        
        return Future { promise in
            DispatchQueue.main.async {
                metadataProvider.startFetchingMetadata(for: url) { (metadata, error) in
                    if let metadata = metadata{
                        promise(Result.success(metadata))
                    } else if let error = error{
                        promise(Result.failure(error))
                    } else {
                        fatalError()
                    }
                }
            }
        }.eraseToAnyPublisher()
    }
}

struct ContentView: View {
    @StateObject var model = ContentModel()
    
    var body: some View{
        NavigationView{
            ScrollView{
                //Changing to Lazy view (LazyVStack, LazyHStack, or LazyVGrid) causes
                //The CPU to stay at 100% even after all links have been fetched
                VStack(spacing: 20){
                    ForEach(model.links){ link in
                        LinkView(richLink: link)
                    }
                }
            }
            .overlay(ProgressView().opacity(model.isLoading ? 1 : 0).scaleEffect(2.5))
            .navigationTitle("Rich Links")
            .toolbar{
                ToolbarItem(placement: .navigationBarTrailing){
                    Button("Fetch"){
                        model.fetchLinks()
                    }.disabled(model.isLoading)
                }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}


class RichLink: NSObject, Identifiable {
    var id: Int!
    var metadata: LPLinkMetadata!
    
    init(for metadata: LPLinkMetadata) {
        super.init()
        id = Int(Date.timeIntervalSinceReferenceDate)
        self.metadata = metadata
    }
}


struct LinkView: UIViewRepresentable {
    var richLink: RichLink
    
    func makeUIView(context: Context) -> LPLinkView {
        guard let metadata = richLink.metadata else {
            return LPLinkView()
        }
        let linkView = LPLinkView(metadata: metadata)
        return linkView
    }
    
    func updateUIView(_ uiView: LPLinkView, context: Context) {
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}