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

@Published变量更新但SwiftUI视图if/else未切换状态问题

问题描述

在FeedViewModel中定义了@Published类型的loading变量,用于控制FeedView切换加载视图与已加载视图。ViewModel初始化时设置loading = true以显示进度视图,预期从Firestore加载完数据后将其设为false,从而切换到已加载视图。但实际情况是,无论loading变量更新为true还是false,视图始终停留在初始状态:设置loading = true时一直显示LoadingView,设为false则一直显示LoadedView。

已尝试的解决方法包括:将DispatchQueue.main.asyncAfter移入Firestore请求闭包、移除DispatchQueue调用、改用视图内的State变量。打印结果显示loading的布尔值确实已变为false,但视图始终无法切换到else分支。且相同的加载/已加载逻辑在其他视图中可正常工作,仅在此视图失效。


FeedViewModel 代码
class FeedViewModel: ObservableObject {
        
    @Published var followingPosts = [Post]()
    @Published var posts = [Post]()
    @Published var loading = true
    
    let service = FeedService()

    init() {
        if self.followingPosts.isEmpty {
            fetchAllPosts()
        } else {
            fetchFollowingPosts()
        }
    }
    
    func fetchFollowingPosts() {
        guard let userid = Auth.auth().currentUser?.uid else { return }
        
        service.fetchFollowingPosts(forUid: userid) { posts in
            self.followingPosts = posts

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            self.loading = false
        }
        }
    }
    
    func fetchAllPosts() {
        service.fetchAllPosts { posts in
            self.posts = posts
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            self.loading = false
        }
        }
    }
}

FeedView 代码
struct FeedView: View {
    @StateObject var viewModel = FeedViewModel()
    
    var body: some View {
        if viewModel.loading {
            LoadingView
        } else {
            LoadedView
        }
    }
}

extension FeedView {
    
    var LoadedView: some View {
        VStack (spacing: 0) {
            
            Image("logo")
                .resizable()
                .frame(width: 48, height: 54)
            
            ScrollView(.vertical, showsIndicators: false) {
                
                PullToRefresh(coordinateSpaceName: "pullToRefresh") {
                    viewModel.fetchFollowingPosts()
                }
                
                if viewModel.followingPosts.isEmpty {
                    Group {
                        Divider()
                        VStack (alignment: .leading, spacing: 12) {
                            Image("wave")
                                .renderingMode(.template)
                                .resizable()
                                .frame(width: 36, height: 36)
                                .foregroundColor(.accentColor).opacity(0.25)

                                Text("Welcome")
                                    .font(Font.headline)
                                    .foregroundColor(Color(.label))
                                
                        }
                        .padding()
                        
                        Divider()
                    }
                    
                    LazyVStack(spacing: 24) {
                        ForEach(viewModel.posts.shuffled().prefix(10), id: \.id) { post in
                            FeedCell(viewModel: FeedCellViewModel(post: post))
                        }
                    }
                    
                } else {
                    LazyVStack (spacing: 24) {
                        ForEach(viewModel.followingPosts, id: \.id) { post in
                            FeedCell(viewModel: FeedCellViewModel(post: post))
                        }
                    }
                }
            }
            .coordinateSpace(name: "pullToRefresh")
        }
    }
    
    var LoadingView: some View {
        VStack (spacing: 24) {
            Image("logo")
                .resizable()
                .frame(width: 48, height: 54)
            Spacer()
            ProgressView()
            Spacer()
        }
        .frame(maxWidth: .infinity)
    }
}

FeedService 代码
struct FeedService {

    func fetchFollowingPosts(forUid uid: String, completion: @escaping([Post]) -> Void) {
        var posts = [Post]()
        
        COLLECTION_FOLLOWING.document(uid).collection("user-following")
            .getDocuments { snapshot, _ in
                guard let documents = snapshot?.documents else { return }
                
                documents.forEach { doc in
                    let userId = doc.documentID
                    
                    COLLECTION_POSTS.whereField("uid", isEqualTo: userId)
                    
                        .getDocuments { snapshot, _ in
                            guard let documents = snapshot?.documents else { return }
                            let post = documents.compactMap({ try? $0.data(as: Post.self) })
                            posts.append(contentsOf: post)
                            
                            completion(posts.sorted(by: { $0.timestamp.dateValue() > $1.timestamp.dateValue()
                            }))
                        }
                }
            }
    }

    func fetchAllPosts(completion: @escaping([Post]) -> Void) {
        COLLECTION_POSTS.getDocuments { snapshot, _ in
            guard let documents = snapshot?.documents else { return }
            let posts = documents.compactMap({ try? $0.data(as: Post.self) })
            completion(posts)
        }
    }
}

内容的提问来源于stack exchange,提问作者amelia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:45:00