SwiftUI中@Published变量在视图中无法更新的问题求助
问题解决:主视图获取异步加载的用户数量
问题原因
你的问题核心是异步操作的时序问题:getUsers()内部发起的是网络请求,属于异步执行逻辑。当你调用usersList.getUsers()后,代码会立刻执行后续的打印语句,此时网络请求还未完成,users数组仍是初始空状态,所以打印结果为0。而ViewModel里的打印语句是在请求成功的回调中执行的,此时数据已经更新,因此能得到正确的用户数量。
解决方案
方法1:利用SwiftUI自动视图更新(推荐)
SwiftUI会自动监听@Published修饰的变量变化,当users数组更新时,视图会自动刷新。你可以直接在视图中使用usersList.users.count,无需手动处理异步回调:
struct MainView: View { @StateObject private var usersList = UserInfoViewModel() var body: some View { VStack { Image("lunchscreen") // 数据更新后会自动刷新显示正确数量 Text("用户数量:\(usersList.users.count)") } .onAppear(perform: download_Users) } func download_Users() { usersList.getUsers() } }
方法2:给ViewModel添加完成回调
如果需要在数据加载完成后执行特定逻辑(比如打印、后续业务处理),可以给getUsers()方法添加回调闭包:
修改ViewModel:
class UserInfoViewModel: ObservableObject { @Published var users:[UserDetails] = [] func getUsers(completion: (() -> Void)? = nil){ let defaults = UserDefaults.standard guard let token = defaults.string(forKey: "jsonwebtoken") else { completion?() return } APIServices().userInfo(token: token) { (result) in switch result { case .success(let accounts): DispatchQueue.main.async { self.users = accounts.map(ZoneViewModel.init) print("Number of users in UserInfoViewModel = \(self.users.count)") // 数据更新后触发回调 completion?() } case .failure(let error): print(error.localizedDescription) completion?() } } } }
修改主视图的download_Users方法:
func download_Users() { usersList.getUsers { // 此闭包会在数据更新完成后执行 print("Number of users in Main view = \(self.usersList.users.count)") } }
方法3:用onReceive监听数据变化
通过SwiftUI的onReceive修饰符,监听users变量的发布事件,当数组更新时执行对应逻辑:
struct MainView: View { @StateObject private var usersList = UserInfoViewModel() var body: some View { Image("lunchscreen") .onAppear(perform: download_Users) // 监听users数组的变化 .onReceive(usersList.$users) { updatedUsers in print("Number of users in Main view = \(updatedUsers.count)") } } func download_Users() { usersList.getUsers() } }
内容的提问来源于stack exchange,提问作者Sherko77
相关产品推荐
相关产品推荐

