Swift 可选择任何类型的铸件

Swift 可选择任何类型的铸件,swift,generics,casting,Swift,Generics,Casting,我正在处理一组表示实体及其属性的类,这些类可以从实体动态创建编辑器表视图。这些属性使用泛型来捕获属性类型。为了使用KVO并生成自动setter,这些属性包含一个键路径。下面是property类的一个非常简化的版本: class XUEntityProperty<Entity: NSManagedObject, Value> { let keyPath: String var customSetter: ((Entity, Value) -> Void)?

我正在处理一组表示实体及其属性的类,这些类可以从实体动态创建编辑器表视图。这些属性使用泛型来捕获属性类型。为了使用KVO并生成自动setter,这些属性包含一个键路径。下面是property类的一个非常简化的版本:

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)
    }
}

您可以通过添加一个虚拟协议来检查可选类型,并使用
is
进行类型检查,然后在
镜像(…)
之后从可选
任意
中提取实际类型值:

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" */

这就是解决方案。需要一些变通方法,但可以根据需要工作。感谢@dfri对协议的理解

private protocol _XUOptional {

    var objectValue: AnyObject? { get }

}

extension Optional: _XUOptional {

    /// This property will return nil if the value is nil,
    /// or if the value isn't castable to AnyObject. String,
    /// Int, Bool and a few others are automatically converted
    /// to their ObjC counterparts.
    var objectValue: AnyObject? {
        switch self {
        case .None:
            return nil
        case .Some(_):
            return self! as? AnyObject
        }
    }

}

let any: Any = Optional<String>("123")
let obj = (any as! _XUOptional).objectValue!
obj.dynamicType /// _NSContiguousString.Type
private protocol\u可选{
var objectValue:AnyObject?{get}
}
扩展可选:xuxu可选{
///如果值为nil,则此属性将返回nil,
///或者如果该值不能强制转换为AnyObject.String,
///Int、Bool和其他一些自动转换
///给他们的ObjC对手。
var objectValue:AnyObject{
切换自身{
案例:无:
归零
案例。一些(uu):
返回自我!作为?任何对象
}
}
}
任选:任选=可选(“123”)
让obj=(任意为!\u可选)。objectValue!
obj.dynamicType//\n连续字符串.Type

使用
镜像查看我的更新答案
;请注意,您仍然需要声明
any
实际上是可选的:如果您使用
let any:any=String(“123”)
进行测试,上述解决方案将由于强制转换(
as!
)到
(可选的)
,而产生运行时异常。我个人更喜欢
镜像
解决方案,因为您不需要扩展基本的
可选
类型,但可以仅使用“外部”方法工作。当然,可选的强制展开用于测试目的。在实际代码中,这看起来很像
if let optional=obj as_XUOptional{return optional.objectValue}
。或者更短的-
(obj as?\u XUOptional)?.optionValue
。无论如何,谢谢你的回答,我真的很高兴能让它工作!几乎花了整个下午的时间来解决这个问题!没关系,
object=(任意为?\xuxuoptional)?.objectValue
工作非常灵活,干得好!:)
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")                       */
private protocol _XUOptional {

    var objectValue: AnyObject? { get }

}

extension Optional: _XUOptional {

    /// This property will return nil if the value is nil,
    /// or if the value isn't castable to AnyObject. String,
    /// Int, Bool and a few others are automatically converted
    /// to their ObjC counterparts.
    var objectValue: AnyObject? {
        switch self {
        case .None:
            return nil
        case .Some(_):
            return self! as? AnyObject
        }
    }

}

let any: Any = Optional<String>("123")
let obj = (any as! _XUOptional).objectValue!
obj.dynamicType /// _NSContiguousString.Type