Swift 4中如何将URLSession请求函数移至网络类并使用完成回调
没问题,我来帮你把这个网络请求逻辑迁移到独立类里,并用completion handler来传递结果。这样你的视图控制器就能专注于UI逻辑,网络层也能更好地复用~
第一步:创建独立的网络管理类
我们先把网络请求逻辑封装到一个NetworkManager类里,用Result类型来统一处理成功/失败的结果,同时移除原本放在网络层的UI代码(网络层不该负责UI逻辑)。
import Foundation // 先确保你的ArticleStruct遵循Codable协议(必须的,否则JSONDecoder无法解析) // struct ArticleStruct: Codable { // // 这里定义你的结构体属性,比如: // // let id: Int // // let title: String // // let content: String // } class NetworkManager { // 用单例模式让这个类全局可访问(也可以根据需求用实例化方式) static let shared = NetworkManager() // 私有化初始化方法,确保只能通过单例访问 private init() {} /// 发起JSON请求并返回解析后的Article数组 /// - Parameters: /// - urlString: 请求的URL字符串 /// - completion: 请求完成后的回调,传递Result类型的结果 func getJsons(from urlString: String, completion: @escaping (Result<[ArticleStruct], Error>) -> Void) { // 验证URL合法性 guard let url = URL(string: urlString) else { let invalidURLError = NSError( domain: "NetworkError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的请求地址"] ) completion(.failure(invalidURLError)) return } // 发起网络请求 URLSession.shared.dataTask(with: url) { data, _, error in // 处理网络请求错误 if let error = error { completion(.failure(error)) return } // 处理空数据情况 guard let responseData = data else { let noDataError = NSError( domain: "NetworkError", code: -2, userInfo: [NSLocalizedDescriptionKey: "未获取到服务器返回的数据"] ) completion(.failure(noDataError)) return } // 解析JSON数据 do { let articles = try JSONDecoder().decode([ArticleStruct].self, from: responseData) completion(.success(articles)) } catch let decodingError { completion(.failure(decodingError)) } }.resume() } }
第二步:在MainViewController中调用
在你的主视图控制器(对应你说的MainActivity)的viewDidLoad里调用这个网络方法,处理结果并更新UI:
import UIKit class MainViewController: UIViewController, UITableViewDataSource { @IBOutlet weak var myTableView: UITableView! private var myJsonDataMainActivity: [ArticleStruct] = [] override func viewDidLoad() { super.viewDidLoad() myTableView.dataSource = self fetchPictureData() } private func fetchPictureData() { let requestURL = "http://192.168.178.100/getPicture.php" NetworkManager.shared.getJsons(from: requestURL) { [weak self] result in // 所有UI操作必须回到主线程 DispatchQueue.main.async { switch result { case .success(let articles): // 赋值并刷新表格 self?.myJsonDataMainActivity = articles self?.myTableView.reloadData() print("成功获取到 \(articles.count) 条图片数据") case .failure(let error): // 这里处理错误,比如弹出提示框 let alert = UIAlertController( title: "加载失败", message: error.localizedDescription, preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "确定", style: .default)) self?.present(alert, animated: true) } } } } // MARK: - UITableViewDataSource func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return myJsonDataMainActivity.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PictureCell", for: indexPath) let article = myJsonDataMainActivity[indexPath.row] // 配置单元格内容,比如 cell.textLabel?.text = article.title return cell } }
第三步:在其他类中调用
其他视图控制器的调用逻辑几乎一致,只是请求URL和数据存储变量不同:
import UIKit class OtherViewController: UIViewController, UITableViewDataSource { @IBOutlet weak var otherTableView: UITableView! private var myJsonDataOtherClass: [ArticleStruct] = [] override func viewDidLoad() { super.viewDidLoad() otherTableView.dataSource = self fetchOtherData() } private func fetchOtherData() { let requestURL = "http://192.168.178.100/getData.php" NetworkManager.shared.getJsons(from: requestURL) { [weak self] result in DispatchQueue.main.async { switch result { case .success(let articles): self?.myJsonDataOtherClass = articles self?.otherTableView.reloadData() case .failure(let error): let alert = UIAlertController( title: "加载失败", message: error.localizedDescription, preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "确定", style: .default)) self?.present(alert, animated: true) } } } } // MARK: - UITableViewDataSource func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return myJsonDataOtherClass.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) let article = myJsonDataOtherClass[indexPath.row] // 配置单元格内容 return cell } }
几个关键注意点
- 避免循环引用:用
[weak self]捕获self,防止闭包持有视图控制器导致内存泄漏 - 主线程更新UI:所有UI操作(比如刷新表格、弹出提示框)必须放在
DispatchQueue.main.async里执行 - 单一职责原则:网络类只负责网络请求和数据解析,UI逻辑交给视图控制器处理,这样代码更清晰、易维护
内容的提问来源于stack exchange,提问作者user8200389
相关产品推荐
相关产品推荐

