在 SwiftUI 中滚动时,许多项目列表崩溃,我该如何解决?

Posted

技术标签:

【中文标题】在 SwiftUI 中滚动时,许多项目列表崩溃,我该如何解决?【英文标题】:List of a lot of items crash when scrolling in SwiftUI, How can I fix it? 【发布时间】:2021-02-13 10:20:54 【问题描述】:

我在 SwiftUI 中有一个简单的项目列表,如下所示:

                    ForEach((1...50), id: \.self) 
                        Text("\($0)….........")
                        Text("\($0)….........")
                        Text("\($0)….........")
                        Text("\($0)….........")
                    

我在使用更复杂的视图时遇到了同样的问题,但我在这里只用一个文本视图对其进行了简化。它会产生同样的问题

崩溃错误:

2021-02-13 21:03:07.124039+1100 rawateb[1696:71245] [ServicesDaemonManager] interruptionHandler is called. -[FontServicesDaemonManager connection]_block_invoke
2021-02-13 21:03:07.163944+1100 rawateb[1696:71245] XPC connection interrupted
Message from debugger: Terminated due to signal 9

那么,我怎样才能在不崩溃的情况下处理一大堆项目

更新

我的完整代码是

//
//  CalendarView.swift
//  rawateb
//
//  Created by Hatim Hoho on 7/2/21.
//

import SwiftUI
import Combine
import QGrid


struct CalendarView: View 
    
    
    
    //@ObservedObject var viewModel = CalendarViewModel()
    @EnvironmentObject var settings: UserSettings
    @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
    @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
    @State var saleries = [FutureSalery]()

    var body: some View 
        ScrollView 
            VStack 
                GeometryReader  geometry in
                    
                    
                    HStack
                        Button(action: 
                            print("Button was tapped")
                            // add new future salery
                            self.addFutureSalery()
                        ) 
                            Image(systemName: "plus.circle")
                                .resizable()
                                .foregroundColor(.blue)
                                
                        
                        .padding()
                        .frame(width: 70, height: 70, alignment: .center)


                        Text("رواتب الأشهر القادمة")
                            .font(.title2)
                            .bold()
                            .multilineTextAlignment(.center)
                            .foregroundColor(Color("labelColor"))
                            
                        Button(action: 
                            print("Button was tapped")
                            self.removeFutureSalery()
                        ) 
                            Image(systemName: "minus.circle")
                                .resizable()
                                .foregroundColor(.blue)
                                
                        
                        .padding()
                        .frame(width: 70, height: 70, alignment: .center)

                    
                    .padding([.top, .bottom], 38)
                    .offset(y: geometry.frame(in: .global).minY > 38 ? -geometry.frame(in: .global).minY+38 : 0)
                    
                    .frame(width: geometry.size.width)
                    .blur(radius: -geometry.frame(in: .global).minY * 0.38)
                
                .frame(height: 150)
                
                
                Spacer()
                
                //List 
                    ForEach((1...50).reversed(), id: \.self) 
                        Text("\($0)….........")
                        Text("\($0)….........")
                        Text("\($0)….........")
                        Text("\($0)….........")
                    

              
               // 
//                QGrid(self.saleries, columns: 2)  salery in
//                    SaleryCellItem2(salery: salery)
//                
//                .padding()
            
        
    


struct SaleryCellItem : View 
    var salery: FutureSalery
    
    var body: some View 
        GeometryReader(content:  geometry in
            HStack 
                Text("\(salery.remainingDays)")
                    
                    .frame(width: geometry.size.width / 3, height: geometry.size.height, alignment: .center)
                
                
                VStack(alignment: .trailing) 
                    Text(salery.hjDateString)
                    Text(salery.acDateString)
                
                .frame(width: geometry.size.width / 3 * 2, height: geometry.size.height, alignment: .trailing)
                .offset(CGSize(width: -45, height: 0))
                
            
        )
        .frame(width: .none, height: 90, alignment: .center)
        .background(Color("listItemBGColor"))
        .cornerRadius(8)
    



struct SaleryCellItem2 : View 
    var salery: FutureSalery
    
    var body: some View 
            VStack 
                Text("\(salery.remainingDays)")
                    
                
                
                VStack(alignment: .trailing) 
                    Text(salery.hjDateString)
                    Text(salery.acDateString)
                
                
            
        


extension CalendarView 
    func addFutureSalery() 
        // get the last salery in list
        var lastDate = Date()
        if (saleries.count > 0) 
            lastDate = saleries.last!.dateObject
        
        
        var dayOfSalery = 1
        switch settings.organizationType 
        case SaleryOrgType.gov.rawValue:
            dayOfSalery = 27
        case SaleryOrgType.privateSector.rawValue:
            dayOfSalery = Int(UserDefaults.standard.double(forKey: "saleryDayIfPrivateSector"))
        case SaleryOrgType.taqaod.rawValue:
            dayOfSalery = 20
        default:
            dayOfSalery = 1
        
        
        // if list is empty -> get the soonest salery from today date
        // get the next salery after that salery
        // append
        var nearestDate = Date()
        if (saleries.count > 0) 
            nearestDate = lastDate.nextMonthDate(withDayNumber: dayOfSalery)
            
         else 
            // first item
            nearestDate = lastDate.nearestDate(withNumber: dayOfSalery)
            
        
        
        self.saleries.append(FutureSalery(dateObject: nearestDate))
        print("count \(self.saleries.count)")
        
    
    
    func removeFutureSalery() 
        if(self.saleries.count > 0) 
            self.saleries.removeLast()
        
        print("count \(self.saleries.count)")
        
    



struct DateItem: Identifiable 
    var id = UUID()
    var title:String


struct CalendarView_Previews: PreviewProvider 
    static var previews: some View 
        Group 

            CalendarView()
                .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro Max"))
               .previewDisplayName("iPhone 11 Pro Max")

        

    


【问题讨论】:

你能显示更多代码吗?如果我将上面的代码嵌入到 List 中,我看不到任何问题。 ScrollView 没有自己的内部几何图形,因此无论是间隔还是几何阅读器都不应该在顶层。这可能是崩溃的原因(渲染引擎而不是循环寻找布局的锚点)。 【参考方案1】:

感谢@Asperi 在 cmets 中提供解决方案。

问题在于几何阅读器。

GeometryReader 不应该在 ScrollView 中,因为它会导致内存泄漏。

所以,只要我们有这样的代码

        ScrollView 
            VStack 
                 GeometryReader(content:  geometry in   // <- look at this
                 ...

应该改成这个

    GeometryReader(content:  geometry in   // <- look at this
        ScrollView 
            VStack 
                 ...

谢谢

【讨论】:

以上是关于在 SwiftUI 中滚动时,许多项目列表崩溃,我该如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

滚动列表中的项目时丢弃 SwiftUI 状态

在 SwiftUI 中使用模态视图删除列表中的项目时崩溃

取消选择 SwiftUI 列表中的项目会使应用程序崩溃

SwiftUI - 防止列表在项目选择时将滚动位置重置为顶部

列表不滚动(在 SwiftUI 中——为了消除其他问题的歧义)

当 Swiftui Picker 滚动其列表时触发的事件