Swift 4:"非名义类型' T'不支持显式初始化"

时间:2017-11-17 10:35:16

标签: ios swift generics

我正在使用此扩展程序来检索urlSession回调中的HTTP标头:

extension HTTPURLResponse {

    func get(_ header: String) -> String? {
        let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }

        if let headerValue = keyValues.filter({ $0.0 == header.lowercased() }).first {
            return headerValue.1
        }
        return nil
    }

}

这很好用,我可以像这样检索标题元素:

    if let metaInt = httpResponse.get("icy-metaint") {
        self.icyMetaInt = Int(metaInt)
    }

现在我想通过引入一个通用函数来使它变得更优雅:

func getHeader<T>(_ httpResponse: HTTPURLResponse, _ headerName: String) -> T? {
        guard let element = httpResponse.get(headerName) else {
            return nil
        }
        return T(element)
}

目的是使用这样的陈述:

self.icyMetaInt = getHeader(httpResponse, "icy-metaint")

我相信像C#这样的东西会起作用。但Swift编译器抱怨道:

  

非名义类型&#39; T&#39;不支持显式初始化

代表

return T(element)

即使我使用

return T.init(element) 

有没有机会实现我的想法?

编辑:添加T? (编辑时一定丢失了)

1 个答案:

答案 0 :(得分:0)

这是因为编译器不知道它应该调用哪个初始化器,因为你正在做的事情太过笼统,就像错误所说的那样。 你想要实现的目标是什么,但实施取决于你所取得的成就。

简而言之,如果您希望能够初始化许多不同的类型,无论是原语还是对象,您应该定义一个新协议,扩展每个类型以实现您认为合适的协议并限制T类型这个协议。

实施例

protocol HTTPHeaderProtocol {
    init(_ headerProtocolString: String?)
}

class MyCustomObject: HTTPHeaderProtocol {
    var myString = ""
    required init(_ headerProtocolString: String?) {
        self.myString = headerProtocolString ?? ""
    }

}

extension String: HTTPHeaderProtocol {
    init(_ headerProtocolString: String?) {
        self.init(headerProtocolString)
    }
}

extension Int: HTTPHeaderProtocol {
    init(_ headerProtocolString: String?) {
        self.init(headerProtocolString)
    }
}

extension HTTPURLResponse {

    func get(_ header: String) -> String? {
        let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }

        if let headerValue = keyValues.filter({ $0.0 == header.lowercased() }).first {
            return headerValue.1
        }
        return nil
    }
    func getHeader<T:HTTPHeaderProtocol>(_ httpResponse: HTTPURLResponse, _ headerName: String) -> T? {
        guard let element = httpResponse.get(headerName) else {
            return nil
        }
        return T(element)
    }
}

这将有效,希望有所帮助:)