我的类有一个属性,在其他语言中,它将是一个简单的字符串数组,它将在对象的实例化中初始化。在Swift中,我提出了以下内容:
class Foo {
var myArray: (String!)[]!
init(arraySize: Int, sourceOfData: SomeOtherClass){
myArray = Array<(String!)>(count: arraySize, repeatedValue:nil)
/* ... code to set the elements of the array using sourceOfData ... */
}
}
这是我能够编译允许预分配数组元素的代码的唯一方法。但是,我认为所有这些感叹号都会让我的代码难以阅读。
我知道我可以将repeatedValue
更改为任意非零字符串,并将类型简化为String[]!
,但这将是一个黑客攻击。
另外,我可以这样做:
class Foo {
let myArray: String[] = []
init(sourceOfData: SomeOtherClass){
/*loop over sourceOfData*/{
myArray.append(/* computed String value */)
}
}
}
然而,这显然性能更差,因为编译器无法猜测我的Array的长度并为其分配连续的内存块。通常情况下,我不太关心优化代码的这一部分的性能,但是对于这个类而言,它是至关重要的。
有没有办法在不影响性能的情况下使用易读类型?
答案 0 :(得分:4)
只要您在myArray
填充init()
,就不需要将sourceOfData
标记为可选。如果你可以使用地图循环class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = sourceOfData.map {
return $0.computeStringValue()
}
}
}
,那么这样就可以了:
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray = Array<String>(count: SomeOtherClass.count, repeatedValue: "")
for i, item in enumerate(sourceOfData) {
myArray[i] = item.computeStringValue()
}
}
}
如果你真的做需要使用一个循环,并且你至少可以确定你需要多大的数组,你可以这样做:
{{1}}
关于性能的最后一点注意事项:LLVM是一个非常复杂的编译器。你说它显然是更糟糕的性能&#34;,但这是静态分析实际上可以确定数组的适当大小的那种代码。我建议使用您的用例的实际数据对其进行分析。
答案 1 :(得分:2)
您可以在Array上使用reserveCapacity方法。这将确保有足够的预分配内存来保存您的数据。
class Foo {
var myArray: String[]
init(sourceOfData: SomeOtherClass) {
myArray.reserveCapacity(sourceOfData.count)
// loop over data calling .append()
}
}