Swift:如何将Decodable.Protocol对象保存到变量?

问题描述 投票:1回答:1

在我的应用程序中,几个控制器的代码结构非常相似,差异很小,因此为了优化,我决定为这些控制器创建一个基础,并从该基础继承每个特定的控制器。

我具有用于发送网络请求和处理响应的功能,我将响应结构作为参数传递给此函数,以便该函数向我返回现成的响应结构。每个此类结构均为Decodable

这种结构的示例:

struct APIAnswerUserActivity: Decodable {
    let status: String
    let code: Int?
    let data: [UserActivity]?
    let total: Int?
}

用于网络请求的功能,Decodable.Protocol类型的对象(结构)被接受为jsonType参数:

public func networkRequest<T: Decodable> (
    url: String,
    timeout: Double = 30,
    method: URLMethods = .GET,
    data: [String : String]? = nil,
    files: [URL]? = nil,
    jsonType: T.Type,
    success: @escaping (T) -> Void,
    failure: @escaping (APIError) -> Void
) -> URLSessionDataTask { ... }

主控制器中有几个参数,我要通过子控制器中的覆盖来覆盖,这些参数之一应该是类型为Decodable的对象,以便常规功能正确接收数据。响应的JSON结构非常相似,但仍然略有不同,由于数据仍然有些不同,因此无法为其创建通用结构。

如果在主控制器中执行此操作:

public var decodableType: Decodable.Type {
    return APIAnswerUserActivity.self
}

这将起作用,并且可以重新定义类型,但是网络功能不接受此类型,它需要Decodable.Protocol对象。如果为变量decodable.Protocol指定了类型decodableType,则不再可以添加APIAnswerUserActivity.self,当调用networkRequest函数时,该值将被静默接受。

在这种情况下怎么办?我希望我能够正确正确地阐明问题的实质。谢谢!

ios swift swift-protocols decodable swift-data
1个回答
0
投票

@@ладиславАртемьев,由于您尚未共享采用Decodable类的代码,我仍然不确定我是否完全理解该问题。但是问题似乎与如何传递Decodable类有关。

我希望以下内容可以帮助阐明如何将正确的约束强加给泛型,以及如何声明变量。您可以将其粘贴到操场上并进行实验。

import Foundation

struct FakeToDo: Decodable {
    var userId: Int
    var id: Int
    var title: String
    var completed: Bool
}

enum URLMethods {
    case GET
    case POST
}

func networkRequest<T: Decodable> (
    url: String,
    timeout: Double = 30,
    method: URLMethods = .GET,
    data: [String : String]? = nil,
    files: [URL]? = nil,
    jsonType: T.Type,
    success: @escaping (T) -> Void,
    failure: @escaping (Error) -> Void
) -> URLSessionDataTask {

    let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { (data, response, error) in
        if error != nil {
            failure(error!)
            return
        }

        guard let data = data else { return }

        let decoder = JSONDecoder()
        guard let value = try? decoder.decode(T.self, from: data) else { return }

        // get back on the main queue for UI
        DispatchQueue.main.async {
            success(value)
        }
    })
    return task
}

class Example<T> where T: Decodable {
    let type: T.Type

    init(_ type: T.Type) {
        self.type = type
    }

    public var decodableType: T.Type {
        return type
    }
}

let decodableType = Example(FakeToDo.self).decodableType

let url = "https://jsonplaceholder.typicode.com/todos/1"
let task = networkRequest(url: url, jsonType: decodableType,
                          success: { value in print(value) },
                          failure: { error in print(error) })

task.resume()

© www.soinside.com 2019 - 2024. All rights reserved.