我正在为我继承的Web API框架添加更好的错误处理。目前它会进行一系列强制转换,当数据与预期的数据不匹配时会导致崩溃。
我想用一个检查类型的函数替换as!
的所有用法,并在失败时引发异常(带有详细描述)。
这是我到目前为止所做的:
func checkType<T>(type: AnyClass, value: T?, name: String) throws -> T {
guard let value = value else {
let message = "[\(name)] Expected \(type), but value was nil"
throw PlaidsterError.InvalidType(message)
}
guard value.dynamicType.self == type else {
let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType.self) with value: \(value)"
throw PlaidsterError.InvalidType(message)
}
return value
}
但这有很多问题。它只能接受对象类型,如果类不完全匹配则失败(例如NSString因为它实际上是__NSCFString而失败),并且它不能用于任何类型,即String,Int,Double ......
我似乎无法为AnyClass
值类型找到Any
的同义词,这是第一个问题。此外,它似乎无法执行value.dynamicType.self is type
之类的操作,因为它表示type
不是类型。
我可以做我想做的事吗?有没有更好的方法来进行这种类型检查,而没有遍布解析代码的大量样板代码?
我的目标是得到类似的东西,甚至更简单:
public struct PlaidCategory {
// MARK: Properties
public let id: String
public let hierarchy: [String]
public let type: String
// MARK: Initialization
public init(category: [String: Any]) throws {
id = try checkType(String.self, value: category["id"], name: "id")
hierarchy = try checkType([String].self, value: category["hierarchy"], name: "hierarchy")
type = try checkType(String.self, value: category["type"], name: "type")
}
}
答案 0 :(得分:3)
您可以使用另一个泛型类型参数编写类似的内容。
func checkType<T, U>(type: U.Type, value: T?, name: String) throws -> U {
guard let value = value else {
let message = "[\(name)] Expected \(type), but value was nil"
throw PlaidsterError.InvalidType(message)
}
guard let result = value as? U else {
let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType) with value: \(value)"
throw PlaidsterError.InvalidType(message)
}
return result
}
并将其用作:
do {
let n: Any = 3
let t = try checkType(Int.self, value: n, name: "n")
print(t) //->3
} catch let error {
print(error)
}
do {
let n: Any = "x"
let t = try checkType(Int.self, value: n, name: "n")
print(t)
} catch let error {
print(error) //->InvalidType("[n] Expected Int, but it was an _NSContiguousString with value: x")
}
我希望这适用于您的PlaidCategory.init(category:)
,但未经过测试。
还有一个。如果仅在返回类型可推断的情况下使用它,则无需传递type
参数。
func checkType<T, U>(value: T?, name: String) throws -> U {
guard let value = value else {
let message = "[\(name)] Expected \(U.self), but value was nil"
throw PlaidsterError.InvalidType(message)
}
guard let result = value as? U else {
let message = "[\(name)] Expected \(U.self), but it was an \(value.dynamicType) with value: \(value)"
throw PlaidsterError.InvalidType(message)
}
return result
}
并将其用作:
do {
let n: Any = "x"
let t: Int = try checkType(n, name: "n")
print(t)
} catch let error {
print(error) //->InvalidType("[n] Expected Int, but it was an String with value: x")
}
或:
public struct PlaidCategory {
// MARK: Properties
public let id: String
public let hierarchy: [String]
public let type: String
// MARK: Initialization
public init(category: [String: Any]) throws {
id = try checkType(category["id"], name: "id")
hierarchy = try checkType(category["hierarchy"], name: "hierarchy")
type = try checkType(category["type"], name: "type")
}
}