【问题标题】:Why is Enum as an optional in a protocol requirements behaving weird?为什么 Enum 作为协议要求中的可选选项表现得很奇怪?
【发布时间】:2018-04-16 07:48:48
【问题描述】:

enum 我已经:

enum APIMethod: String {
    case GET
    case POST
}

我将protocol 定义为:

protocol APIResource {
    associatedtype Model: Codable
    var base: String { get }
    var path: String { get }
}
extension APIResource {
    var method: APIMethod? { // To be able to have the conforming type ignore if it wants
        return nil // Actually, this will return a valid case but not now
    }
    var request: URLRequest {
        let url = URL(string: base + path)!
        var request = URLRequest(url: url)
        request.httpMethod = method?.rawValue
        return request
    }
}

现在,当我在我的 struct 中采用它时,我会提供它自己的 method,例如:

struct MyResource: APIResource {
    typealias Model = MyCodableModelStructure
    let base = "http://---.com"
    let path = "/pathToResource"
    let method = APIMethod.POST
}

但是在计算 request 属性时,request.httpMethod 不会得到 "POST" 的值。


然后我尝试做一些不同的事情。我将enum 要求从extension 移到protocol 本身。

protocol APIResource {
    associatedtype Model: Codable
    var base: String { get }
    var path: String { get }
    var method: APIMethod? { get }
}
extension APIResource {
    var request: URLRequest {
        let url = URL(string: base + path)!
        var request = URLRequest(url: url)
        request.httpMethod = method?.rawValue
        return request
    }
}

当我将它移到协议本身时,我得到了错误:

类型'MyResource'不符合协议'APIResource'

所以我不得不将MyResource重新定义为:

struct MyResource: APIResource {
    typealias Model = MyCodableModelStructure
    let base = "http://---.com"
    let path = "/pathToResource"
    // See! I was forced to annotate the type
    let method: APIMethod? = APIMethod.POST
    // Or, otherwise, I tried with rawValue without annotating the type
    // let method = APIMethod(rawValue: "POST")
}

此时,request 属性与request.httpMethod = "POST" 成功计算。


编辑:

实际上我的APIResource 有一个associatedtype。因此,我创建了一个通用类:

class MyAPIRequest<T: APIResource> {
    let resource: T
    init(resource: T) {
        self.resource = resource
    }
}

然后我将MyResourceMyAPIRequest初始化为:

let apiResource = MyResource()
let apiRequest = MyAPIRequest(resource: apiResource)
apiRequest.load {
    // async task with completion block
}


所以,我的问题是:

  • 为什么一开始在扩展中添加属性不起作用?
  • 为什么它在添加到协议定义本身时会起作用?
  • 最后,为什么我不得不使用 annotatingrawValue 初始化器?

【问题讨论】:

  • let method: APIMethod?改成var method: APIMethod?
  • 但是在计算请求属性时,request.httpMethod 没有得到值“POST”。我根本没有经历过这种行为......你也可以吗请展示如何实例化该结构?
  • @holex 查看我的编辑
  • @CZ54 基本上不能解决我遇到的问题。 letvar 都不会让我摆脱类型注释。

标签: swift enums swift-protocols


【解决方案1】:
  1. 如果我们在 Extension 中定义了任何属性并且没有在 Protocol 中声明它,那么它只会获取扩展值。不管你有没有重新定义。

  2. 当你在协议中定义它时,它会被覆盖,所以你可以获得子值。

  3. 这里的声明是可选的,您在其中传递了非可选值。所以你必须告诉价值的类型。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2014-02-05
    • 1970-01-01
    • 2023-01-07
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2021-10-11
    • 2018-09-09
    相关资源
    最近更新 更多