如何在关联类型协议中指定数组中的元素类型

问题描述 投票:0回答:1
struct ApiResult: HandyJSON {}

struct Api: BaseRequest {
    typealias DataType = [ApiResult]
}

let api = Api()

api.call.subscribe { onSuccess: result
    // i hope get a array of ApiResult class
}

error!

如何才能达到与下面相同的结果?

enter image description here

ios swift rx-swift
1个回答
0
投票

我不完全确定我理解了这个问题,但这可以编译并且可能就是你想要的:

protocol BaseRequest {
    associatedtype DataType
    var call0: Single<Data> { get }
}

struct ApiResult: Decodable { }

struct Api: BaseRequest {
    typealias DataType = [ApiResult]
    var call0: RxSwift.Single<Data>
}

extension BaseRequest where DataType == [ApiResult] {
    var call: Single<DataType?> {
        self.call0.map { DataType.deserialize(from: $0) }
    }
}

extension Array where Element == ApiResult {
    static func deserialize(from data: Data) -> [ApiResult] {
        (try? JSONDecoder().decode([ApiResult].self, from: data)) ?? []
    }
}

let api = Api(call0: .just(Data()))

api.call.subscribe(onSuccess: { result in
    // `result` is an `[ApiResult]` as you wanted.
})

也就是说,这感觉是一个非常奇怪的设置。我更喜欢这样的东西:

// this part is the custom code for your endpoint
struct ApiResult: Decodable { }

extension Endpoint where Response == [ApiResult] {
    static var apiResults: Endpoint {
        // make your request here
        let request = URLRequest(url: URL(string: "whatever")!)
        return Endpoint(request: request, decoder: JSONDecoder())
    }
}

let api = Api(data: URLSession.shared.rx.data(request:)) // pass in a mock for testing.

api.call(endpoint: .apiResults)
    .subscribe(onSuccess: { apiResults in
        // here you go.
    })

// this part is the reusable library. It will work for every conceivable
//   REST request, no matter how complex.
struct Endpoint<Response> {
    let request: URLRequest
    let response: (Data) throws -> Response

    init(request: URLRequest, response: @escaping (Data) throws -> Response) {
        self.request = request
        self.response = response
    }
}

extension Endpoint where Response: Decodable {
    init(request: URLRequest, decoder: TopLevelDecoder) {
        self.request = request
        self.response = { try decoder.decode(Response.self, from: $0) }
    }
}

extension Endpoint where Response == Void {
    init(request: URLRequest) {
        self.request = request
        self.response = { _ in }
    }
}

class Api {
    let data: (URLRequest) -> Observable<Data>
    
    init(data: @escaping (URLRequest) -> Observable<Data>) {
        self.data = data
    }

    func call<Response>(endpoint: Endpoint<Response>) -> Single<Response> {
        data(endpoint.request)
            .map(endpoint.response)
            .asSingle()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.