Alamofire请求数据后数组未更新致TableView无显示及崩溃问题
1. 单例与实例混用导致数据不共享
你在ViewController里同时创建了networkingProvider实例,又调用了NetworkingProvider.shared.getUser(),这是两个完全独立的NetworkingProvider对象:
- 调用单例的
getUser()后,数据存在单例的users数组里 - 但你打印的是自己创建的
networkingProvider实例的users.count,自然是0
修复方法:统一使用单例,删除ViewController里的var networkingProvider = NetworkingProvider(),所有操作都用NetworkingProvider.shared:
// ViewController的viewDidLoad里修改: override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "myCustomCell") // 调用单例的getUser,同时传入闭包监听数据加载完成 NetworkingProvider.shared.getUser { [weak self] in DispatchQueue.main.async { self?.tableView.reloadData() } } }
2. 异步请求后正确刷新TableView
网络请求是异步执行的,不能在viewDidLoad里直接调用reloadData(),必须等请求完成后再刷新,而且UI操作必须在主线程。同时避免NetworkingProvider直接持有ViewController(会导致循环引用和EXC_BAD_ACCESS),改用闭包回调通知ViewController数据更新:
修改NetworkingProvider的getUser方法:
var users: [User] = [] func getUser(completion: @escaping () -> Void) { AF.request("https://randomuser.me/api/?results=1", method: .get) .validate(statusCode: 200..<300) // 替换你的statusOK,确保是有效的状态码范围 .responseDecodable(of: UserResult.self) { [weak self] response in guard let self = self else { return } if let user = response.value?.results { self.users = user print(user.count) // 这里会输出1 completion() // 通知ViewController数据加载完成 } else { print(response.error?.errorDescription ?? "No error") completion() // 即使出错也回调,避免UI一直等待 } } }
3. 修正Model解析错误
你的User结构体里address字段定义为String?,但randomuser.me的API返回的地址是嵌套对象(包含street、city、state等),会导致解析失败(当前请求1条数据可能没触发崩溃,但后续会有问题)。修正Model结构:
struct UserResult: Decodable { let results: [User]? } struct User: Decodable { var name: Name? var email: String var gender: String? var location: Location? // 替换原来的address,对应API的location字段 var phone: String? } struct Name: Decodable { var first: String? } struct Location: Decodable { var street: Street? var city: String? var state: String? } struct Street: Decodable { var number: Int? var name: String? }
4. 确保TableView数据源正确指向单例的users数组
在ViewController的numberOfRowsInSection和cellForRowAt方法里,要使用单例的users数组:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return NetworkingProvider.shared.users.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "myCustomCell", for: indexPath) as! CustomTableViewCell let user = NetworkingProvider.shared.users[indexPath.row] cell.textLabel?.text = user.name?.first ?? "Unknown" // 其他字段赋值 return cell }
5. 解决EXC_BAD_ACCESS错误
之前的错误是因为你可能在NetworkingProvider里直接持有了ViewController的强引用(比如self.viewController),导致循环引用,对象无法释放,访问时出现野指针。改用闭包回调(上面的completion参数),并且在闭包中使用[weak self]避免循环引用,就能解决这个问题。
内容的提问来源于stack exchange,提问作者burlesque

