巷がRxSwiftで盛り上がっている中、昨日try! Swiftの発表のスライドを見返していました。
そんな中、このスライドで挙げられている、NSValueTransformer
をswiftyに扱う手法が紹介されていたのですが、
これがスライド通りにコードを書いても うまく動いてくれない ので、動くように修正してみました。
動かないのが嫌だった…
修正してみた
元のコードは、スライド内にかかれているので省略します。
class ValueTransformer<A, B>: NSValueTransformer {
typealias Transform = A? -> B?
typealias ReverseTransform = B? -> A?
private let transform: Transform
private let reverseTransform: ReverseTransform
init(transform: Transform, reverseTransform: ReverseTransform) {
self.transform = transform
self.reverseTransform = reverseTransform
super.init()
}
override static func transformedValueClass() -> AnyClass {
return AnyObject.self
}
override class func allowsReverseTransformation() -> Bool {
return true
}
override func transformedValue(value: AnyObject?) -> AnyObject? {
return transform(value as? A).flatMap { $0 as? AnyObject }
}
override func reverseTransformedValue(value: AnyObject?) -> AnyObject? {
return reverseTransform(value as? B).flatMap { $0 as? AnyObject }
}
}
変更点としては、
- <A, B> にかかっていた
AnyObject
の制約を外した - transformedValueClass() で返す型を
AnyObject.self
に変更 - transform, reverseTransform で帰ってきた値を flatMap を使って
AnyObject?
に変換するように変更
になります。これで、スライドにあった例の通りに動作します。
// ValueTransformer<String, NSUUID> と明記してもok!
let transformer = ValueTransformer(transform: {
return NSUUID(UUIDString: $0 ?? "")
}, reverseTransform: {
return $0?.UUIDString
})
let uuid = transformer.transformedValue(NSUUID().UUIDString)
_ = transformer.reverseTransformedValue(uuid)
もちろん、AnyObjectであることが条件になるので、NSValueTransformerを拡張したこの ValueTransformer は、structやenumの型には適応できません。
もし、変換のclosureを渡すことで任意の型から型への変換をするなら、ikesyoさんの作ったHimotoki内にあるTransformerを参考に作ってみるといいのかなって思いました。
ここにあるTransformerは単方向ですが、NSValueTransformerのように逆方向もサポートしたら面白そう。