【问题标题】:Swift: How to save a Decodable.Protocol object to a variable?Swift:如何将 Decodable.Protocol 对象保存到变量中?
【发布时间】:2020-04-29 04:56:38
【问题描述】:

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

我有一个发送网络请求和处理响应的函数,我把响应结构作为参数传递给这个函数,让函数返回一个现成的响应结构给我。每个这样的结构都是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 对象。如果为变量decodableType指定了decodable.Protocol类型,那么就不能再添加APIAnswerUserActivity.self,在调用networkRequest函数时会悄悄接受。

遇到这种情况怎么办?我希望我能够正确、清楚地说明我的问题的本质。谢谢!

【问题讨论】:

  • "几个控制器的代码结构非常相似,差异很小,所以为了优化我决定为这些控制器创建一个基础,并从基础继承每个特定的控制器。"你称之为“控制器”的东西是什么?
  • @ElTomato,我有 UserActivityTableViewController、UserInvoicesTableViewController 等。在这些控制器中,无限滚动的方法用于在到达表格末尾时从网络加载数据。我创建了 InfinityScrollTableViewController 并在这个控制器上移动了所有常见的逻辑。在创建 UserActivity 控制器时,我会这样做: class UserActivityTableViewController: InfinityScrollTableViewController { ... }
  • @ElTomato 所有 UITableViewControllers 有 90% 的相似性,差异很小。我认为值得在 1 个控制器中实现所有相似之处,并从中继承每个特定的控制器并仅重新定义必要的方法。
  • 在上面的部分源代码(构建 URLSessionDataTask 的代码)中查看由省略号 ({ ... }) 表示的代码会很有帮助。这大概就是问题所在。你能把它包括进来吗?
  • @iamtimmo,我在 InfinityScrollTableViewController 中有一个 getElementsFromNetwork 方法,这个方法运行 networkRequest 方法(我在上面留下了它的代码)。由于networkRequest方法需要Decodable类型作为必填参数,所以必须传递。我试图在 InfinityScrollTableViewController 中将 public var 创建为 Decodable.Protocol 类型并在附属 TableViewController 中覆盖它,但我得到编译错误。

标签: ios swift swift-protocols decodable swift-data


【解决方案1】:

@Владислав Артемьев,我仍然不确定我是否完全理解了这个问题,因为你没有分享使用Decodable 类的代码。但问题似乎是关于如何通过Decodable 类。

我希望以下内容可以帮助阐明如何对泛型施加正确的约束以及应如何声明变量。您可以将其粘贴到 Playground 中并进行实验。

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()

【讨论】:

  • 如何覆盖这个变量?在 InfiniteScrollTableViewController 我创建函数 getElementsFromNetwork,该函数从 API 获取数据。我创建了 UserActivityTableViewController:InfiniteScrollTableViewController 和 UserInvoicesTableViewController:InfiniteScrollTableViewController。在 InfiniteScrollTableViewController 中,我创建了 public var decodableType,我想在 UserActivityTableViewController 和 UserInvoicesTableViewController 中覆盖这个 var。函数 getElementsFromNetwork 运行到 InfiniteScrollTableViewController。
  • 请为此创建一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
相关资源
最近更新 更多