Swift: для L oop конечное условие оценивается только один раз? - PullRequest
1 голос
/ 10 апреля 2020

Я пытаюсь понять, как Swift обрабатывает циклы for-in.

Обзор : мы перебираем строки NSOutlineView. Если условие выполнено, мы расширяем элемент, который, очевидно, изменяет общее количество строк в layoutView.

Предварительное условие : OutlineView имеет 5 элементов "root". У каждого из них есть 5 дочерних элементов.


Пример

final class anOutlineView: NSOutlineView
{
    override func reloadData()
    {
        super.reloadData()

        for i in 0 ..< self.numberOfRows
        {
            // Assume we expand the item at row 0, which increases 
            // the overall outlineView row count from 5 to 10.
        }
    }
}

В этом подходе l oop останавливается, когда i == 4. Я предполагаю, что это потому, что Swift оценивает диапазон только один раз, когда он впервые сталкивается с ним? Есть ли способ изменить это поведение так, чтобы условия каждый раз переоценивались через l oop, как традиционный for l oop?

Замена for l oop с while l oop, очевидно, работает и является хорошим решением. Я просто пытаюсь понять нюансы Swift, потому что это поведение не то, что я ожидал. В Objective- C условия for l oop оценивались на каждой итерации, и это была хорошо известная оптимизация производительности - воздерживаться от вызова self.property в условиях l oop (если не было веской причины, как в этом случае.)

1 Ответ

1 голос
/ 10 апреля 2020

0 ..< self.numberOfRows представляет собой Range и, в частности, Sequence. Итерация по последовательности выполняется путем создания итератора, а затем вызова его метода next() до тех пор, пока итератор не будет исчерпан, сравнивайте IteratorProtocol:

Всякий раз, когда вы используете для -в l oop с массивом, множеством или любой другой коллекцией или последовательностью, вы используете итератор этого типа. Swift использует внутренний итератор последовательности или коллекции для включения языковой конструкции for-in l oop.

Итак,

for i in 0 ..< self.numberOfRows {
    ...
}

эквивалентно

let range = 0 ..< self.numberOfRows
var it = range.makeIterator()
while let i = it.next() {
    ...
}

Изменение numberOfRows во время итерации не изменяет диапазон (который является типом значения) или итератор, и, следовательно, не влияет на количество итераций.

...