在讨论这个问题之前,我将首先解释我想要做什么以及我是如何陷入困境的。
作为我自己的学习练习,我解决了一些已经在 Objective-C 中解决的问题,看看如何使用 Swift 以不同的方式解决它们。我遇到的具体情况是一个小片段,它捕获更改之前和之后的值,并在两者之间进行插值以创建动画的关键帧。
为此我有一个目标Capture
包含对象的属性、关键路径和两个id
之前和之后的值的属性。后来,当对捕获的值进行插值时,我确保可以通过将每个值包装在一个Value
使用类簇根据其包装的值的类型返回适当的类的类,或者nil
对于不支持的类型。
这是可行的,我也可以按照相同的模式使其在 Swift 中工作,但感觉不像 Swift。
什么有效
我没有将捕获的值包装为启用插值的方式,而是创建了一个Mixable
当类型支持必要的基本算术时,类型可以遵循的协议并使用协议扩展:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
这部分工作得非常好,并强制执行同质混合(类型只能与其自己的类型混合),而 Objective-C 实现中并未强制执行。
我被困住的地方
下一个逻辑步骤,这就是我陷入困境的地方,似乎是让每个 Capture 实例(现在是一个结构)保存两个相同可混合类型的变量,而不是两个AnyObject
。我还将初始化参数从对象和关键路径更改为返回对象的闭包()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
当可以推断类型时,这有效,例如:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
但不使用键值编码,它返回 AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
错误:无法使用类型为“(() -> _)”的参数列表调用类型“Capture”的初始值设定项
AnyObject
不符合Mixable
协议,所以我可以理解为什么这不起作用。但我可以检查对象到底是什么类型,并且由于我只涵盖了少数可混合类型,因此我认为我可以涵盖所有情况并返回正确的 Capture 类型。太见了if这甚至可以工作我做了一个更简单的例子
一个更简单的例子
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
当类型推断得到保证时,它会起作用:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
但当闭包可以返回不同类型时则不然
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
错误:无法使用类型为“(() -> _)”的参数列表调用类型“Foo”的初始值设定项
我什至无法自己定义这样的闭包。
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
错误:无法推断当前上下文中的闭包类型
我的问题
这是可以做的事情吗?可以使用条件来确定泛型的类型吗?或者是否有另一种方法来保存相同类型的两个变量,其中类型是根据条件决定的?
Edit
我真正想要的是:
- 捕获更改之前和之后的值并保存该对(旧+新)以供以后使用(同类对的异构集合)。
- 遍历所有收集的值并删除无法插值的值(除非此步骤可以与收集步骤集成)
- 单独插入每个同质对(混合旧+新)。
但在解决这个问题时,这个方向似乎是一个死胡同。我将不得不后退几步并尝试不同的方法(如果我再次陷入困境,可能会问一个不同的问题)。