You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中View与含API调用的类间传递十六进制参数的最佳方案

实现方案

首先先修正现有代码的两处核心问题:

  1. ObservableObject 类中不能使用@State属性包装器,@State仅适用于SwiftUI View结构体内部的状态管理
  2. 原代码仅在类初始化时调用一次接口,没有提供外部触发重新请求的入口

第一步:改造API调用类(ViewModel)

我们做以下调整:

  • 修正属性包装器错误,将请求参数postHashHex改为@Published可监听属性
  • 新增可主动调用的请求方法,支持外部传入十六进制参数
  • 优化参数生成逻辑,改用系统JSON序列化避免字符串拼接的转义错误
  • 可选添加防抖逻辑,避免输入过程中频繁触发接口请求
import Combine

// 符合Swift命名规范,类名首字母大写
class FetchResultsViewModel: ObservableObject {
    @Published var clout = Cloutington()
    @Published var dataHasLoaded = false
    @Published var postHashHex: String = ""
    // 用于监听属性变化的订阅者
    private var cancellable = Set<AnyCancellable>()
    
    init() {
        // 可选:监听postHashHex变化,防抖500ms后自动发起请求
        $postHashHex
            .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
            .removeDuplicates()
            .filter { !$0.isEmpty } // 空值不请求
            .sink { [weak self] hex in
                self?.getData(postHashHex: hex)
            }
            .store(in: &cancellable)
    }
    
    // 公开请求方法,支持外部传入参数调用
    func getData(postHashHex: String) {
        // 改用JSON序列化生成参数,避免转义错误
        let parameters = ["PostHashHex": postHashHex]
        guard let postData = try? JSONSerialization.data(withJSONObject: parameters) else {
            return
        }
        
        var request = URLRequest(url: URL(string: "https://bitclout.com/api/v0/get-single-post")!, timeoutInterval: 10) // 不要用无穷超时
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = postData
        request.httpMethod = "POST"
        
        let task = URLSession.shared.dataTask(with: request) { [weak self] responseData, response, error in
            guard let self = self, let resData = responseData, error == nil else {
                print(error ?? "请求错误")
                return
            }
            
            do {
                let finalData = try JSONDecoder().decode(Cloutington.self, from: resData)
                DispatchQueue.main.async {
                    self.clout = finalData
                    self.dataHasLoaded = true
                }
            } catch {
                print("解析错误: \(error)")
            }
        }
        task.resume()
    }
}

第二步:改造View层代码

将TextField的输入内容和ViewModel的参数绑定即可,两种可选交互方式:

  1. 输入过程中自动触发请求(配合ViewModel的防抖逻辑)
  2. 新增查询按钮,用户点击后才发起请求(避免无效请求,更推荐)

这里提供更常用的带查询按钮的实现:

import SwiftUI

struct TestingText: View {
    @StateObject var viewModel = FetchResultsViewModel()
    @Binding var text: String
    
    var body: some View {
        VStack(spacing: 20) {
            TextField("Paste Clout Hexcode Here", text: $text)
                .font(.title2)
                .padding()
                .border(.gray)
                // 可选:按回车键也触发请求
                .onSubmit {
                    viewModel.postHashHex = text
                }
            
            Button {
                // 点击按钮将输入内容传给ViewModel发起请求
                viewModel.postHashHex = text
            } label: {
                Text("查询内容")
                    .font(.title3)
                    .padding(.horizontal, 30)
                    .padding(.vertical, 10)
                    .background(.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
            
            Text(viewModel.clout.postFound?.body ?? "暂无数据")
        }
        .padding()
    }
}

struct TestingText_Previews: PreviewProvider {
    static var previews: some View {
        TestingText(text: .constant("8004bb672ad3f46118775cd4b2cb5306c63f6d68787457990bf0d2fda3f7993a"))
    }
}

核心逻辑说明

  • 用@Published修饰ViewModel的postHashHex属性,既可以接收View层传入的输入内容,也可以自身监听变化自动触发请求
  • 避免了数据跨层传递的冗余代码,符合SwiftUI的MVVM设计规范
  • 输入和请求逻辑分离,后续要加输入校验、加载状态等扩展都很方便

内容的提问来源于stack exchange,提问作者DeveloperDanK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 19:06:03