我要在UIlabel
中添加文本及其性能成本(我已经使用了构建时间分析器using this link)。我如何优化此代码?
for value in model?.offerings ?? [] {
offeringsLabel.text = offeringsLabel.text! + " | " + (value.name ?? "") + "," + (value.type ?? "")//this addition cost to performance
}
我也尝试过[ array].joined
,但这并没有什么区别
答案 0 :(得分:5)
首先,提出基本问题。为什么这么慢?根据我的经验,链接+
是导致大量编译时性能问题的最常见原因。这是因为+
有很多重载(我在4.2的stdlib中算出103)。 Swift不仅需要证明+
可以按需在(String, String)
上使用。它必须证明没有其他可能的同等有效的重载组合(如果存在,那将是模棱两可的,并且是一个错误)。这不仅包括简单的情况,例如(Int,Int)。它还包括适用于(String,String)的复杂的基于协议的重载,但不如(String,String)那样精确:
static func + <Other>(lhs: String, rhs: Other) -> String
where Other : RangeReplaceableCollection, Character == Other.Element
这需要很长时间,因为当您将一堆+
链接在一起时,它具有爆炸性。每个子表达式都必须根据可能返回的所有内容进行重新考虑。
如何解决?首先,在这种情况下,我不会使用for
循环来逐步构建一个字符串。只需map
每个Offering
到您想要的字符串,然后将它们连接在一起:
offeringsLabel.text = model?.offerings
.map { "\($0.name ?? ""),\($0.type ?? "")" }
.joined(separator: " | ")
这不仅可以更快地编译,而且IMO更清楚了您在做什么。它还不需要!
,这很好。 (还有其他方法可以解决此问题,但这是一个很好的副作用。)
也就是说,这也表明您的模型中可能存在问题。这是一个单独的问题,但我仍然会认真对待。任何时候只要您的代码如下:
optionalString ?? ""
您需要问,这真的是可选的吗?您真的将nil名称与空名称区别对待吗?如果没有,我相信name
和type
应该只是String
而不是String?
,然后变得更加简单。
offeringsLabel.text = model?.offerings
.map { "\($0.name),\($0.type)" }
.joined(separator: " | ")
此代码与您的代码略有不同。当model
为nil
时,您的代码将独自离开offeringsLabel
。我的代码清除了文本。这就提出了一个更深层的问题:model
为nil时为什么要运行此代码?为什么model
是可选的?您可以使它在数据中成为非可选,还是在此方法的前面使用guard let model = model else { return }
?
根据我的经验,Swift过于复杂的常见原因是对Optional的过度使用。 Optional是非常重要且功能强大的,但是除非您真的表示“毫无价值是合法的,而且不同于'空',否则,您不应该使用它。”
答案 1 :(得分:2)
我的建议是首先在description
对象中添加属性Offering
,以正确处理name
和value
(您的解决方案始终在{{1} }和name
,无论value
是否具有值)
name
使用var description : String? {
let desc = [name, value].compactMap{$0}.joined(separator:",")
return desc.isEmpty ? nil : desc
}
和compactMap
joined
答案 2 :(得分:1)
您可以使用UILabel
首先获取完整的字符串
Array.reduce
并在下一个迭代中再次读取文本
let fullString = (model?.offerings ?? []).reduce("", { string, value in
string + " | " + (value.name ?? "") + "," + (value.type ?? "")
}
offeringsLabel.text = fullString
反复设置text
会影响性能,因为例如,它可能会触发动态调整尺寸标签的尺寸重新计算
答案 3 :(得分:0)
您可以尝试添加函数,例如:
let valueName = value.name ?? ""
offeringsLabel.text?.append(valueName)
答案 4 :(得分:0)
您应该在此处使用temp变量。
如果在复杂的表达式中使用运算符??
,可能会大大增加编译时间
因此您可以使用以下代码更新代码(是的,它并不短,但是我们应该帮助编译)
let offerings = model?.offerings ?? []
var offeringsText = ""
for value in offerings {
let name = value.name ?? ""
let type = value.type ?? ""
let valueText = " | " + name + "," + type
let offeringsText = offeringsText + valueText
}
offeringsLabel.text = offeringsText
希望这对您有帮助!