ios开发: 从接口获取数据列表并显示
一,代码
1,接口返回的json
{
"status": "success",
"code": 200,
"time": "2026-03-29 21:39:27",
"msg": "",
"data": {
"list": [
{
"id": 1,
"author": "李白",
"title": "静夜思",
"image": "https://imgs-qn.test.com/ware/sowhatimg/ware/orig/2/39/39653.png"
},
{
"id": 2,
"author": "孟浩然",
"title": "宿建德江",
"image": "https://imgs-qn.test.com/ware/sowhatimg/ware/orig/2/39/39651.png"
},
{
"id": 3,
"author": "杨万里",
"title": "晓出净慈寺送林子方",
"image": "https://imgs-qn.test.com/ware/slider/1938.png"
},
{
"id": 4,
"author": "李白",
"title": "望庐山瀑布",
"image": "https://imgs-qn.test.com/ware/slider/1938.png"
},
{
"id": 5,
"author": "author5",
"title": "title5",
"image": "https://imgs-qn.test.com/ware/goods/big/2/284/284909.jpg"
},
{
"id": 6,
"author": "author6",
"title": "title6",
"image": "https://imgs-qn.test.com/ware/goods/big/2/284/284909.jpg"
}
]
}
}
2, 列表页面
ContentView
//
// ContentView.swift
// helloworld2
//
// Created by liuhongdi on 2026/3/28.
//
import SwiftUI
import Alamofire
struct ContentView: View {
@State private var message = "加载中..."
var urlString = "http://www.test.net/list.php";
@State private var poems: [Poem] = [] // 存储解析后的数组
var body: some View {
NavigationStack {
VStack {
Text(message)
List(poems) { poem in
// value: poem 会将整个对象传递给路由系统
NavigationLink(value: poem) {
HStack(spacing: 15) {
AsyncImage(url: URL(string: poem.image)) { image in
image.resizable().aspectRatio(contentMode: .fit)
} placeholder: {
ProgressView()
}
.frame(width: 90, height: 90)
.background(Color.purple)
.cornerRadius(8)
VStack(alignment: .leading, spacing: 5) {
Text(poem.title).font(.headline)
Text(poem.author).font(.subheadline).foregroundColor(.secondary)
}
}
}
}
.navigationTitle("古诗精选")
// 路由拦截器:当检测到目的地传递的值是 PoemItem 类型时,跳转到 DetailView
.navigationDestination(for: Poem.self) { poem in
DetailView(id: poem.id)
}
}
}
.task {
await fetchData()
}
}
/// 获取数据
func fetchData() async {
let request = AF.request(urlString).serializingDecodable(ApiResponse<PoemListData>.self)
let response = await request.response
switch response.result {
case .success(let apiResponse):
// 这里的 apiResponse.data 就是 PoemListData 类型
self.poems = apiResponse.data.list
print("请求成功,时间:\(apiResponse.time)")
case .failure(let error):
print("解析错误: \(error)")
}
}
}
#Preview {
ContentView()
}
3,详情页面
DetailView
import SwiftUI
struct DetailView: View {
let id: Int // 接收传递过来的 id
var body: some View {
VStack(spacing: 20) {
Text("诗词详情页")
.font(.title)
Text("当前查看的诗词 ID 是: \(id)")
.padding()
.background(Color.purple.opacity(0.1))
.cornerRadius(10)
Spacer()
}
.navigationTitle("详情")
// SwiftUI 默认在导航跳转时提供“从右向左”的滑动动画
}
}
4,model类
ApiResponse
import Foundation
// 使用泛型 T,并约束 T 必须符合 Decodable 协议
struct ApiResponse<T: Decodable>: Decodable {
let status: String
let code: Int
let time: String
let msg: String
let data: T // 这里可以是任何类型:List 结构体、单个对象、甚至是一个数组
}
// 针对你当前接口的具体数据结构
struct PoemListData: Decodable {
let list: [Poem]
}
struct Poem: Decodable, Identifiable, Hashable {
let id: Int
let author: String
let title: String
let image: String
}
二,测试效果:

浙公网安备 33010602011771号