SwiftUI应用创建第二个Theme对象时无报错挂起问题排查求助
解决创建第二个Theme时应用挂起的问题
先从你提到的怀疑点和代码里的明显问题逐一排查,大概率能解决这个无响应挂起的情况:
1. 紧急修复:过滤闭包中修改State导致的无限循环
你的Themes视图List过滤逻辑里有一行严重的问题,会直接触发无限视图刷新,最终把CPU占满导致应用挂起:
ForEach(self.firebaseController.userThemesCollatedBySections[section]!.filter({ (theme) -> Bool in themeName = theme.name // 这里每次过滤都会修改@State变量themeName return themeName.hasPrefix(themeController.searchText) || themeController.searchText == "" }), id: \.self) { theme in
每次执行过滤闭包时,你都在修改@State private var themeName,而State的变化会立刻触发视图重新渲染,渲染后又会再次执行过滤闭包修改State,形成无限循环。
修复方法:直接用theme.name判断,不要修改State变量:
ForEach(self.firebaseController.userThemesCollatedBySections[section]!.filter({ theme in theme.name.hasPrefix(themeController.searchText) || themeController.searchText.isEmpty }), id: \.self) { theme in
这个问题是导致应用挂起的最核心原因,优先修复它。
2. 处理你怀疑的SF Symbols渲染问题
你把图标的字体大小设为0来隐藏它,这种做法可能导致iOS渲染引擎出现异常:
.font(.system(size: theme.fixed == true && isSubscribed == false ? 24 : 0, weight: .bold))
建议用opacity或者.hidden()修饰符来控制显示/隐藏,更符合SwiftUI的渲染逻辑:
Image(systemName: "lock.fill") .foregroundColor(charcoalGreyTwo) .font(.system(size: 24, weight: .bold)) // 先判断是否属于个人主题,再判断是否需要显示锁图标 .opacity(theme.sections == "personal themes" ? 0 : (theme.fixed && !isSubscribed ? 1 : 0))
3. 修复Firebase监听器重复添加的问题
你的getUserTheme()方法每次调用都会新增一个.childAdded监听器,不会移除旧的。创建第二个Theme后再次调用这个方法,会导致同一个节点的事件被多次监听,userThemes数组重复添加数据,进而引发List的异常刷新和内存占用飙升。
给FirebaseController添加监听器句柄,每次调用前先移除旧监听器:
// 在FirebaseController中添加变量保存监听器句柄 private var themeListener: DatabaseHandle? func getUserTheme() { // 先移除之前的监听器,避免重复监听 if let listener = themeListener { userDB.removeObserver(withHandle: listener) } guard let currentUser = Auth.auth().currentUser else {return} let user = Users(user: currentUser) let themeUser = userDB.child(user.uid).child("userInfo").child("themes") // 保存新的监听器句柄 themeListener = themeUser.observe(.childAdded, with: { [weak self] snapshot in // 原有解析代码不变 }) }
同时建议在Themes视图的onDisappear中调用停止监听的方法,避免内存泄漏:
.onDisappear { firebaseController.themeListener.map { firebaseController.userDB.removeObserver(withHandle: $0) } }
4. 修复delete方法的逻辑错误
你的delete方法中,themeName是之前过滤时设置的,不一定是被删除的Theme的名称,可能导致Firebase删除错误:
func delete(at offsets: IndexSet) { guard let index = offsets.first else { return } let deletedTheme = firebaseController.userThemes[index] firebaseController.userThemes.remove(atOffsets: offsets) firebaseController.deleteTheme(themeName: deletedTheme.name) firebaseController.getUserTheme() }
先优先修复第1点的无限循环问题,应该就能解决应用挂起的情况,再逐一处理其他问题来优化稳定性。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

