Cha*_*roe 4 generics casting swift
我正在处理一组表示实体及其属性的类,然后可以动态地从实体创建编辑器表视图.这些属性使用泛型来捕获属性类型.为了使用KVO并生成自动设置器,这些属性包含键路径.这是属性类的一个非常简化的版本:
class XUEntityProperty<Entity: NSManagedObject, Value> {
let keyPath: String
var customSetter: ((Entity, Value) -> Void)?
func setValue(value: Value, onEntity entity: Entity) {
/// If custom setter is set, use it.
if let setter = self.customSetter {
setter(entity, value)
return
}
/// Otherwise set the object using the keypath.
guard let objValue = value as? AnyObject else {
XUThrowAbstractException() // Use custom setter
}
entity.setValue(objValue, forKeyPath: self.keyPath)
}
}
Run Code Online (Sandbox Code Playgroud)
几乎任何东西都适用.问题在于选择权问题.例如:
let property = XUEntityProperty<MyEntity, NSDate?>(keyPath: "optionalDate")
这里的问题是,在setValue方法中,强制转换AnyObject将失败,因为值为Optional<NSDate>,即使是,也将返回AnyObject- 无法转换为.objValue as? NSDatenilobjValue.Some(_)
我正在寻找一种解决方案,如何通过检测和展开自动设定器来解决这个问题Optional.
我尝试的任何强制转换都会导致编译器抱怨转换为更可选的类型,或者最终将Optional内部包含在另一个类型中Optional.
有谁知道如何检测一个值的Any 是怎么样的Optional,如果是,提取值从可选,它铸造AnyObject?
举个例子来试试游乐场:
let any: Any = Optional<String>("123")
any.dynamicType // -> Optional<String>.Type
var object: AnyObject? = nil
/// ... -> put value from `any` to `object`.
Run Code Online (Sandbox Code Playgroud)
您可以通过添加伪协议和使用isfor类型检查来检查可选类型,然后Mirror(..)从可选中提取实际类型值Any:
protocol IsOptional {}
extension Optional : IsOptional {}
/* Detect if any is of type optional */
let any: Any = Optional<String>("123")
var object : AnyObject? = nil
switch any {
case is IsOptional:
print("is an optional")
if let (_, a) = Mirror(reflecting: any).children.first {
object = a as? AnyObject
}
default:
print("is not an optional")
} /* Prints "is an optional" */
/* Detect if any2 is of type optional */
let any2: Any = String("123")
switch any2 {
case is IsOptional:
print("is an optional")
// ...
default:
print("is not an optional")
} /* Prints "is not an optional" */
Run Code Online (Sandbox Code Playgroud)
Charlie Monroes自己的最终解决方案非常简洁(+1!).我想我会添加一个补充.
鉴于_XUOptional已经定义了协议并对其进行了Optional类型扩展(如Charlies的回答),您可以any使用可选链接和nil合并运算符处理可选或不在一行中的事件:
let anyOpt: Any = Optional<String>("123")
let anyNotOpt: Any = String("123")
var object: AnyObject?
object = (anyOpt as? _XUOptional)?.objectValue ?? (anyOpt as? AnyObject)
/* anyOpt is Optional(..) and left clause of nil coalescing operator
returns the unwrapped .objectValue: "123" as 'AnyObject' */
object = (anyNotOpt as? _XUOptional)?.objectValue ?? (anyNotOpt as? AnyObject)
/* anyNotOpt is not optional and left-most optional chaining of left
clause returns nil ('anyNotOpt as? _XUOptional' -> nil).
In that case, right clause will successfully cast the non-optional
'Any' type to 'AnyObject' (with value "123") */
Run Code Online (Sandbox Code Playgroud)