#swiftui #swiftui-list #swiftui-foreach
#swiftui #swiftui-список #swiftui-foreach
Вопрос:
У меня есть простой список элементов в 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")
}
}
}
Комментарии:
1. Можете ли вы показать больше кода? Я не вижу никаких проблем, если я вставлю приведенный выше код в список.
2. ScrollView не имеет собственной внутренней геометрии, поэтому ни spacer, ни geometry reader не должны находиться на верхнем уровне. Это может быть причиной сбоя (движок рендеринга скорее задействован в поиске некоторой привязки к макету).
Ответ №1:
Спасибо @Asperi за предоставление решения в комментариях.
Проблема заключается в чтении геометрии.
GeometryReader не должен находиться внутри ScrollView, потому что это вызовет утечку памяти.
Итак, всякий раз, когда у нас есть такой код, как этот
ScrollView {
VStack {
GeometryReader(content: { geometry in // <- look at this
...
он должен быть изменен на этот
GeometryReader(content: { geometry in // <- look at this
ScrollView {
VStack {
...
Спасибо