如何定义一个空的 "uninitialized" 键路径并稍后设置?
How to define an empty, "uninitialized" keypath and set it later?
我编写了一个程序来计算总浏览量 width/height(有时我想要总宽度,有时我想要总高度)。唯一的问题是:如果我正在计算宽度,我想在总数中添加一个额外的 10
。这是我当前的代码:
func calculateLengthOfAllViews(calculatingWidth: Bool) {
let views = [
UIView(frame: CGRect.zero),
UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)),
UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
]
var totalLength: CGFloat = 0
if calculatingWidth {
totalLength += 10 /// add extra 10 if calculating width
} else {
totalLength += 0
}
for view in views { /// add each view's width/height
let length: CGFloat
if calculatingWidth {
length = view.frame.width
} else {
length = view.frame.height
}
totalLength += length
}
print("Total length is \(totalLength)")
}
calculateLengthOfAllViews(calculatingWidth: true) /// Total length is 160.0
calculateLengthOfAllViews(calculatingWidth: false) /// Total length is 100.0
这很好用。但是,我在 2 个地方重复 if calculatingWidth {
,以确定:
- 是否添加额外的padding 10 padding
- 是否使用
view.frame.width
或view.frame.height
作为长度
第二个 if 语句是不必要的,因为它在每次迭代中的计算结果总是相同的。
所以,我认为 keypaths 是可行的方法——我可以从第一个 if 语句中存储对 .width
或 .height
的引用。但是,如何在不“初始化”的情况下定义键路径?我想做这样的事情:
let keyPath: KeyPath /// Reference to generic type 'KeyPath' requires arguments in <...>
if calculatingWidth {
totalLength += 10
keyPath = \UIView.frame.width
} else {
totalLength += 0
keyPath = \UIView.frame.height
}
for view in views {
let length = view[keyPath: keyPath] /// Type of expression is ambiguous without more context
totalLength += length
}
然而,这给了我 Reference to generic type 'KeyPath' requires arguments in <...>
。我该如何解决这个问题?
class KeyPath<Root, Value>
是泛型类型,有两个类型参数:根类型和结果值类型,必须在变量声明中指定。在你的情况下它将是
let keyPath: KeyPath<UIView, CGFloat>
使用该定义,其余代码也可以编译。
您在函数的开头使用了 if
,并且在循环的 每 次迭代中使用了 if
。我认为更好的方法是使用 reduce(into:_:)
来减少条件分支的数量。
代码:
func calculateLengthOfAllViews(calculatingWidth: Bool) {
let views = [
UIView(frame: CGRect.zero),
UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)),
UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
]
let totalLength: CGFloat
if calculatingWidth {
totalLength = views.reduce(10, { [=10=] + .frame.width })
} else {
totalLength = views.reduce(0, { [=10=] + .frame.height })
}
print("Total length is \(totalLength)")
}
我编写了一个程序来计算总浏览量 width/height(有时我想要总宽度,有时我想要总高度)。唯一的问题是:如果我正在计算宽度,我想在总数中添加一个额外的 10
。这是我当前的代码:
func calculateLengthOfAllViews(calculatingWidth: Bool) {
let views = [
UIView(frame: CGRect.zero),
UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)),
UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
]
var totalLength: CGFloat = 0
if calculatingWidth {
totalLength += 10 /// add extra 10 if calculating width
} else {
totalLength += 0
}
for view in views { /// add each view's width/height
let length: CGFloat
if calculatingWidth {
length = view.frame.width
} else {
length = view.frame.height
}
totalLength += length
}
print("Total length is \(totalLength)")
}
calculateLengthOfAllViews(calculatingWidth: true) /// Total length is 160.0
calculateLengthOfAllViews(calculatingWidth: false) /// Total length is 100.0
这很好用。但是,我在 2 个地方重复 if calculatingWidth {
,以确定:
- 是否添加额外的padding 10 padding
- 是否使用
view.frame.width
或view.frame.height
作为长度
第二个 if 语句是不必要的,因为它在每次迭代中的计算结果总是相同的。
所以,我认为 keypaths 是可行的方法——我可以从第一个 if 语句中存储对 .width
或 .height
的引用。但是,如何在不“初始化”的情况下定义键路径?我想做这样的事情:
let keyPath: KeyPath /// Reference to generic type 'KeyPath' requires arguments in <...>
if calculatingWidth {
totalLength += 10
keyPath = \UIView.frame.width
} else {
totalLength += 0
keyPath = \UIView.frame.height
}
for view in views {
let length = view[keyPath: keyPath] /// Type of expression is ambiguous without more context
totalLength += length
}
然而,这给了我 Reference to generic type 'KeyPath' requires arguments in <...>
。我该如何解决这个问题?
class KeyPath<Root, Value>
是泛型类型,有两个类型参数:根类型和结果值类型,必须在变量声明中指定。在你的情况下它将是
let keyPath: KeyPath<UIView, CGFloat>
使用该定义,其余代码也可以编译。
您在函数的开头使用了 if
,并且在循环的 每 次迭代中使用了 if
。我认为更好的方法是使用 reduce(into:_:)
来减少条件分支的数量。
代码:
func calculateLengthOfAllViews(calculatingWidth: Bool) {
let views = [
UIView(frame: CGRect.zero),
UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)),
UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
]
let totalLength: CGFloat
if calculatingWidth {
totalLength = views.reduce(10, { [=10=] + .frame.width })
} else {
totalLength = views.reduce(0, { [=10=] + .frame.height })
}
print("Total length is \(totalLength)")
}