You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:32:34