问题
I have a small debate at work: Is it a good practice to calculate the size of the Array in swift before running over it's items? What would be a better code practice:
Option A:
func setAllToFalse() {
for (var i = 0; i < mKeyboardTypesArray.count; i++ ) {
self.mKeyboardTypesArray[i] = false
}
}
or Option B:
func setAllToFalse() {
let typesCount = mKeyboardTypesArray.count
for (var i = 0; i < typesCount; i++ ) {
self.mKeyboardTypesArray[i] = false
}
}
All, of course, if I don't alter the Array during the loops.
I did go over the documentation, which states this:
The loop is executed as follows:
When the loop is first entered, the initialization expression is evaluated once, to set up any constants or variables that are needed for the loop. The condition expression is evaluated. If it evaluates to false, the loop ends, and code execution continues after the for loop’s closing brace (}). If the expression evaluates to true, code execution continues by executing the statements inside the braces. After all statements are executed, the increment expression is evaluated. It might increase or decrease the value of a counter, or set one of the initialized variables to a new value based on the outcome of the statements. After the increment expression has been evaluated, execution returns to step 2, and the condition expression is evaluated again.
回答1:
The idiomatic way to say this in Swift is:
func setAllToFalse() {
mKeyboardTypesArray = mKeyboardTypesArray.map {_ in false}
}
That way, there is nothing to evaluate and nothing to count.
In fact, this would make a nice Array method:
extension Array {
mutating func setAllTo(newValue:T) {
self = self.map {_ in newValue}
}
}
Now you can just say:
mKeyboardTypesArray.setAllTo(false)
Alternatively, you could do it this way (this involves taking the count, but only once):
mKeyboardTypesArray = Array(count:mKeyboardTypesArray.count, repeatedValue:false)
回答2:
The loop condition is evaluated each time through the loop. Consider this experiment:
extension Array {
var myCount: Int {
get {
println("here")
return self.count
}
}
}
let a = [1, 2, 3, 4, 5]
for var i = 0; i < a.myCount; i++ {
println(a[i])
}
Output:
here
1
here
2
here
3
here
4
here
5
here
You could see a small speed improvement from Option B, but I expect that the count property on Array is not expensive if the array is unchanged. It is potentially a good code practice anyway because it communicates to the reader that you expect the array size to remain constant for duration of the loop.
It is possible that the compiler would optimize array.count by detecting that nothing in the loop modifies the array, but it wouldn't be able to do that for array.myCount because of the println side effect.
回答3:
I have found that it is not, which can cause a crash if you're iterating through an array and removing items (for example). In current Swift syntax, this for loop
for i in 0..<m_pendingCommands.count
{
if m_pendingCommands[i].packetID < command.packetID
{
m_pendingCommands.remove(at: i)
}
}
crashed halfway through the array, with a bad index.
I switched this to a while loop:
var i: Int = 0
while i < m_pendingCommands.count
{
if m_pendingCommands[i].packetID < ID
{
m_pendingCommands.remove(at: i)
}
else
{
i += 1
}
}
来源:https://stackoverflow.com/questions/31235595/is-the-for-loop-condition-evaluated-each-loop-in-swift