ios开发:swiftui分离viewmodel/model/view

一,代码

1,ContentView

//
//  ContentView.swift
//  helloworld2
//
//  Created by liuhongdi on 2026/3/28.
//

import SwiftUI
import Alamofire


struct ContentView: View {
        @State private var message = "加载中..."

        // 初始化 ViewModel
        @StateObject private var viewModel = PoemViewModel()
    
         var body: some View {

             NavigationStack {
                 VStack {
                     Text(message)

                     List {
                         if viewModel.isLoading && viewModel.poems.isEmpty {
                             ProgressView("加载中..")
                         }
                         ForEach(viewModel.poems){ poem in
                             NavigationLink(value: poem) {
                                  PoemRow(poem: poem) // 进一步拆分出子视图
                             }
                         }
                     }
                     .navigationTitle("唐诗鉴赏1")
                     .navigationDestination(for: Poem.self) { poem in
                         DetailView(id: poem.id)
                     }
                     // 调用逻辑
                     .task{
                          await viewModel.fetchData()
                     }
                     .refreshable{
                          await viewModel.fetchData()
                     }

                 }
             }
         }

}


// 一行元素的view
struct PoemRow: View {
    let poem: Poem
    var body: some View {
        HStack(spacing: 15) {
            AsyncImage(url: URL(string: poem.image)) { image in
                image.resizable().aspectRatio(contentMode: .fit)
            } placeholder: {
                Color.purple.opacity(0.1)
            }
            .frame(width: 60, height: 60)
            .background(Color.purple)
            .cornerRadius(8)
            
            VStack(alignment: .leading){
                Text(poem.title).font(.headline)
                Text(poem.author).font(.subheadline).foregroundColor(.secondary)
            }
        }
    }
}

#Preview {
    ContentView()
}

 

2,Contentviewmodel

import Foundation
import Alamofire

@MainActor // 确保 UI 更新在主线程
class PoemViewModel: ObservableObject {
    
    @Published var poems: [Poem] = []
    @Published var isLoading = false
    
    func fetchData() async {
        isLoading = true
        let url = "http://www.test.net/list.php"
        // 使用泛型解析
        let result = await AF.request(url).serializingDecodable(ApiResponse<PoemListData>.self).result
        switch result {
        case .success(let response):
            self.poems = response.data.list
        case .failure(let error):
            print("请求失败:\(error)")
        }
        isLoading = false
    }
}

 

3,model


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
}

 

二,测试效果:

image

 

posted @ 2026-04-04 10:37  刘宏缔的架构森林  阅读(1)  评论(0)    收藏  举报