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

SwiftUI中如何向类传递类型?解决Query类data属性类型报错问题

解决方案

你遇到的问题核心是:type是实例属性,不能直接用作类型标注。正确的做法是把Query改成泛型类,利用Swift泛型绑定数据类型,具体修改如下:

修改后的Query类代码

import Foundation
import Combine

class Query<T: Decodable>: ObservableObject {
    let url: String
    
    init(url: String) {
        self.url = "https://api.domain.com" + url
        // 初始化时自动触发请求,也可以留到外部手动调用
        fetchData()
    }
    
    @Published var data: T?
    @Published var error: Error?
    @Published var hasError: Bool = false
    @Published var isSuccess: Bool = false
    @Published var isLoading: Bool = false
    @Published var isFetching: Bool = false
    
    private var bag = Set<AnyCancellable>()
    
    func fetchData() {
        isLoading = true
        isFetching = true
        
        guard let url = URL(string: self.url) else {
            error = NSError(domain: "Invalid URL", code: -1, userInfo: nil)
            hasError = true
            isLoading = false
            isFetching = false
            return
        }
        
        URLSession.shared.dataTaskPublisher(for: url)
            .receive(on: DispatchQueue.main)
            .tryMap { data, response in
                guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                    throw NSError(domain: "Request failed", code: (response as? HTTPURLResponse)?.statusCode ?? -2, userInfo: nil)
                }
                return data
            }
            .decode(type: T.self, decoder: JSONDecoder())
            .sink(receiveCompletion: { [weak self] completion in
                guard let self = self else { return }
                self.isLoading = false
                self.isFetching = false
                
                switch completion {
                case .finished:
                    self.isSuccess = true
                case .failure(let err):
                    self.error = err
                    self.hasError = true
                    self.isSuccess = false
                }
            }, receiveValue: { [weak self] decodedData in
                self?.data = decodedData
            })
            .store(in: &bag)
    }
}

修改View的使用方式

现在不需要传入type参数,直接通过泛型<Post>指定数据类型:

import SwiftUI

struct AView: View {
    @StateObject var query = Query<Post>(url: "/post/id")
    
    var body: some View {
        if query.isSuccess, let post = query.data {
            Text(post.title)
        } else if query.isLoading {
            ProgressView()
        } else if query.hasError {
            Text("加载失败:\(query.error?.localizedDescription ?? "未知错误")")
        }
    }
}

// 示例Post模型(需符合Decodable协议)
struct Post: Decodable {
    let title: String
    // 其他业务属性...
}

关键说明

  • 泛型<T: Decodable>让Query类适配任意符合Decodable的模型类型,无需单独传递类型参数。
  • 解码时直接使用T.self,编译器会自动根据泛型参数推断具体模型类型。
  • View中通过Query<Post>明确类型后,query.data会自动成为Post?类型,无需额外类型转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 08:28:18