如何在Alamofire请求完成后返回DataModel并传递至ViewController供segue使用
实现方案:异步回调传值
最直接的实现方式是用逃逸闭包做异步回调,把请求得到的PlayerModel实例回传给主ViewController,再通过segue传递到目标页面,具体步骤如下:
步骤1:修改PlayerRequestManager的请求方法,添加回调参数
给fetchPlayerByName新增逃逸闭包作为完成回调,请求完成后无论成功失败都通过闭包把结果回传给调用方:
class PlayerRequestManager { let baseURL = "https://public-api.tracker.gg/v2/csgo/standard/profile/steam/" // 新增completion回调,@escaping标记为逃逸闭包,参数为Result枚举区分成功/失败状态 func fetchPlayerByName(_ playerName: String, completion: @escaping (Result<PlayerModel, Error>) -> Void) { let headers : HTTPHeaders = [ "TRN-Api-Key": "my secret api key", "Accept": "application/json", "Accept-Encoding": "gzip" ] let fullURL = "\(baseURL)\(playerName)" AF.request("\(fullURL)", headers: headers).response { (responseData) in guard let data = responseData.data else { // 无返回数据时回调错误 completion(.failure(NSError(domain: "PlayerRequestError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无返回数据"]))) return } do{ let player = try JSONDecoder().decode(PlayerData.self, from: data) let playerObject = PlayerModel(playerUsername: player.data.platformInfo.platformUserHandle ?? "Error loading data", playerUserID: player.data.platformInfo.platformUserId ?? "Error loading data", avatarURL: player.data.platformInfo.avatarUrl ?? "Error loading data", playerTimePlayed: player.data.segments[0].stats.timePlayed.displayValue ?? "Error loading data", playerKills: player.data.segments[0].stats.kills.displayValue ?? "Error loading data", playerDeaths: player.data.segments[0].stats.deaths.displayValue ?? "Error loading data", playerKD: player.data.segments[0].stats.kd.displayValue ?? "Error loading data", playerDamage: player.data.segments[0].stats.damage.displayValue ?? "Error loading data", playerHeadshots: player.data.segments[0].stats.headshots.displayValue ?? "Error loading data", playerShotsFired: player.data.segments[0].stats.shotsFired.displayValue ?? "Error loading data", playerShotsHit: player.data.segments[0].stats.shotsHit.displayValue ?? "Error loading data", playerShotsAccuracy: player.data.segments[0].stats.shotsAccuracy.displayValue ?? "Error loading data", playerHeadshotPct: player.data.segments[0].stats.headshotPct.displayValue ?? "Error loading data", playerMaychesPlayed: player.data.segments[0].stats.matchesPlayed.displayValue ?? "Error loading data", playerWins: player.data.segments[0].stats.wins.displayValue ?? "Error loading data", playerLosses: player.data.segments[0].stats.losses.displayValue ?? "Error loading data", playerTies: player.data.segments[0].stats.ties.displayValue ?? "Error loading data", playerMVPs: player.data.segments[0].stats.mvp.displayValue ?? "Error loading data", playerMoneyEarned: player.data.segments[0].stats.moneyEarned.displayValue ?? "Error loading data", playerBombsPlanted: player.data.segments[0].stats.bombsPlanted.displayValue ?? "Error loading data", playerBombsDefused: player.data.segments[0].stats.bombsDefused.displayValue ?? "Error loading data", playerHostagesRescued: player.data.segments[0].stats.hostagesRescued.displayValue ?? "Error loading data", playerRoundsPlayed: player.data.segments[0].stats.roundsPlayed.displayValue ?? "Error loading data", playerWLPercentage: player.data.segments[0].stats.wlPercentage.displayValue ?? "Error loading data") // 解码成功,回调player实例 completion(.success(playerObject)) }catch { // 解码失败,回调错误信息 completion(.failure(error)) } } } }
步骤2:主ViewController接收回调,存储数据并触发跳转
首先在主ViewController中声明一个全局存储属性,用于后续segue传值:
// 主ViewController新增属性,存储请求到的玩家数据 var targetPlayer: PlayerModel?
修改搜索按钮点击逻辑,调用请求方法时接收回调,拿到数据后触发跳转:
@IBAction func searchButtonPressed(_ sender: Any) { guard let searchedName = searchField.text, !searchedName.isEmpty else { print("no name entered.") return } playerRequestManager.fetchPlayerByName(searchedName) { [weak self] result in // 切到主队列执行UI相关操作,避免线程错误 DispatchQueue.main.async { guard let self = self else { return } switch result { case .success(let playerObject): // 把请求到的玩家对象赋值给全局属性 self.targetPlayer = playerObject // 触发segue跳转,替换为你自己定义的segue标识符 self.performSegue(withIdentifier: "JumpToPlayerDetailSegue", sender: nil) case .failure(let error): print("请求失败: \(error.localizedDescription)") // 可在这里添加用户可见的错误提示 } } } }
重写主ViewController的prepare(for:sender:)方法,把数据传递给目标ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // 匹配segue标识符,避免误处理其他跳转 if segue.identifier == "JumpToPlayerDetailSegue" { // 替换为你的目标页面类名 guard let detailVC = segue.destination as? PlayerDetailViewController else { return } // 把存储的玩家对象赋值给目标页面对应属性 detailVC.receivedPlayer = self.targetPlayer } }
其他可选实现方式
- 代理模式:给
PlayerRequestManager定义代理协议,主ViewController作为代理接收回调,适合回调逻辑多、场景复杂的项目 - 通知中心:通过
NotificationCenter发送携带player对象的通知,主VC监听通知接收数据,适合一对多数据传递的场景
内容的提问来源于stack exchange,提问作者slimeforest
相关产品推荐
相关产品推荐

