SwiftUI中fetchAuthorArticles首次点击无法获取JSON数据的原因排查
针对你遇到的「首次点击无法获取JSON数据,关闭Sheet后再次点击正常」的问题,我整理了几个最可能的原因及对应的解决办法:
可能的原因1:onAppear 绑定位置不合理
你当前把数据请求的触发逻辑绑定在了 LazyVGrid 的 onAppear 上,而不是整个视图的根容器(ScrollView)上。在Sheet首次弹出时,LazyVGrid 的渲染可能存在延迟,导致 onAppear 没有被及时触发,进而漏掉了首次的数据请求。
可能的原因2:首次打开Sheet时 selectedAuthor.author_id 未正确赋值
如果Sheet是通过列表点击触发的,可能存在「首次点击时 selectedAuthor 还没完成赋值就弹出Sheet」的情况——此时请求URL中的 authorID 是默认值(比如0),服务器返回空数据;而关闭Sheet后再次打开时,selectedAuthor 已经完成赋值,请求的URL正确,自然能拿到数据。
可能的原因3:AuthorService 中 isLoadingPage 属性未正确声明
从代码里能看到你在 fetchAuthorArticles 中使用了 isLoadingPage,但 AuthorService 类里没有把它声明为 @Published 属性。这不仅会导致编译警告,还会让视图无法感知加载状态的变化,间接影响数据更新的反馈逻辑。
对应的解决方案
1. 调整 onAppear 的绑定位置
把 onAppear 移到 ScrollView 上,确保整个视图出现时就触发数据请求:
struct SelectedAuthorView: View { @Binding var selectedAuthor: AuthorPost @ObservedObject var service = AuthorService() var cellNumber: Int = 0 let columns: [GridItem] = Array(repeating: GridItem(.flexible(), spacing: 0), count: 2) var body: some View { ScrollView(.vertical, showsIndicators: true) { LazyVGrid(columns: columns, spacing: 0) { ForEach(Array(service.authorArticles.articles.enumerated()), id: \.1.id) {i, post in AuthorArticleListItem(articlePost: post, cellNumber: i) } .background(Color(.white)) if service.isLoadingPage { ProgressView() .padding() .offset(x: UIScreen.main.bounds.width / 4) } } } // 将onAppear移到ScrollView根容器上 .onAppear { print("触发请求,authorID: \(selectedAuthor.author_id)") // 打印ID验证是否正确 self.service.fetchAuthorArticles(authorID: selectedAuthor.author_id) } } }
2. 确保 selectedAuthor 完全赋值后再弹出Sheet
如果是通过按钮或列表项触发Sheet,要先完成 selectedAuthor 的赋值,再弹出视图。比如用 sheet(item:) 的正确写法:
struct AuthorListView: View { @State private var selectedAuthor: AuthorPost? var body: some View { List(authors) { author in Button(action: { self.selectedAuthor = author // 先完成赋值 }) { Text(author.author_name) } } .sheet(item: $selectedAuthor) { author in SelectedAuthorView(selectedAuthor: .constant(author)) } } }
3. 完善 AuthorService 的属性声明
给 isLoadingPage 添加 @Published 修饰符,确保视图能感知加载状态的变化:
class AuthorService: ObservableObject { @Published var authorArticles = AuthorList(author: Author(author_id: 0, articles: 0, newspaper_image: "", author_name: "", author_image: "", newspaper: ""), articles: []) @Published var isLoadingPage = false // 补充@Published声明 func fetchAuthorArticles(authorID: Int){ isLoadingPage = true // 后续请求代码保持不变 } }
额外调试建议
在 fetchAuthorArticles 里打印请求参数,确认首次请求的 authorID 和 URL 是否正确:
func fetchAuthorArticles(authorID: Int){ isLoadingPage = true print("当前请求的authorID: \(authorID)") let urlString = "http://author/article/list/\(authorID)/" print("请求URL: \(urlString)") if let selectedAuthorUrl = URL(string:urlString) { // 后续请求代码保持不变 } }
通过这些步骤,应该能定位并解决首次点击无法获取数据的问题。
内容的提问来源于stack exchange,提问作者Mert Köksal

