为什么Enum作为协议要求中的可选项表现得很奇怪?

时间:2018-04-16 07:48:49

标签: swift enums swift-protocols

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
}

所以,我的问题是:

  • 为什么在扩展中添加属性并不是首先工作?
  • 为什么它在添加到协议定义本身时才起作用?
  • 最后,为什么我被迫使用注释rawValue初始值设定项?

1 个答案:

答案 0 :(得分:0)

  1. 如果我们在Extension中定义任何属性而不在Protocol中声明它,那么它只会获取扩展值。无论你重新定义与否都无所谓。

  2. 当您在协议中定义它时,它会使其可覆盖,因此您可以获得子值。

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

  4. 希望这有帮助。

相关问题