5

我做了一个程序来计算视图的总宽度/高度(有时我想要总宽度,有时我想要总高度)。唯一的问题是:如果我正在计算宽度,我想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

这工作正常。但是,我if calculatingWidth {在两个地方重复,以确定:

  1. 是否添加额外的padding 10 padding
  2. 是否使用view.frame.widthview.frame.height作为长度

第二个 if 语句是不必要的,因为它在每次迭代中总是计算相同的东西。

所以,我认为键路径是要走的路——我可以存储对第一个 if 语句.width.height来自第一个 if 语句的引用。但是,如何在不“初始化”的情况下定义键路径?我想做这样的事情:

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 <...>. 我怎样才能解决这个问题?

4

2 回答 2

4
class KeyPath<Root, Value>

是一个泛型类型,有两个类型参数:根类型和结果值类型,它们必须在变量的声明中指定。在你的情况下,它会是

let keyPath: KeyPath<UIView, CGFloat>

使用该定义,其余代码也可以编译。

于 2021-08-15T20:29:17.673 回答
4

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, { $0 + $1.frame.width })
    } else {
        totalLength = views.reduce(0, { $0 + $1.frame.height })
    }

    print("Total length is \(totalLength)")
}
于 2021-08-15T20:35:05.187 回答