SWIFT, fatal error (index out of range) при переборе элементов массива
подскажите, почему появляется fatal error при попытке удалить из массива числа у которых остаток от деления = 0? 
Ответы (2 шт):
Ошибка появляется из-за того, что вы удаляете элементы из массива, а цикл, как "создал" себе количество индексов для итераций по стартовому размеру массива, так по нему и пытается пробежаться, вы количество индексов уменьшаете и в итоге он обращается к несуществующему номеру элемента массива.
Кроме того, в этом коде есть еще одна ошибка. Номера элементов массива, созданные для прохода цикла, которые поочередно присваиваются переменной index, остаются неизменными даже после удаления элементов из массива, а вот метод remove(at:) удаляет элементы из массива в соотвествии с их реальными индексами, на момент удаления. И если добавить в ваш код принты:
import Foundation
var array1 = [1, 20, 35, 4, 5, 7, 10]
for (index, value) in array1.enumerated() {
print("Array: ", array1, " index:", index, " Value:", value, " array [\(index)] =", array1[index])
if value % 2 == 0 {
print("value in if = ", value)
array1.remove(at: index)
}
print("Array: ", array1, " index:", index, " Value:", value, " array [\(index)] =", array1[index], "\n")
}
то по выводу в консоли:
Array: [1, 20, 35, 4, 5, 7, 10] index: 0 Value: 1 array [0] = 1
Array: [1, 20, 35, 4, 5, 7, 10] index: 0 Value: 1 array [0] = 1
Array: [1, 20, 35, 4, 5, 7, 10] index: 1 Value: 20 array [1] = 20
value in if = 20
Array: [1, 35, 4, 5, 7, 10] index: 1 Value: 20 array [1] = 35
Array: [1, 35, 4, 5, 7, 10] index: 2 Value: 35 array [2] = 4
Array: [1, 35, 4, 5, 7, 10] index: 2 Value: 35 array [2] = 4
Array: [1, 35, 4, 5, 7, 10] index: 3 Value: 4 array [3] = 5
value in if = 4
Array: [1, 35, 4, 7, 10] index: 3 Value: 4 array [3] = 7
Array: [1, 35, 4, 7, 10] index: 4 Value: 5 array [4] = 10
Array: [1, 35, 4, 7, 10] index: 4 Value: 5 array [4] = 10
Fatal error: Index out of range:
становится видно, что во втором случае срабатывания вашего условия оператор if "ловит" число 4 (которое соответствует условию), а в итоге из массива удаляется число 5 (не соответствующее условию), потому что, до этого, было удалено число 20 и все реальные индексы "съехали"на 1, в отличие от тех, которые себе "сохранил" для итерации for.
Если Вы хотите именно так удалить элементы из массива, то разверните итератор:
var a = [1, 2, 3, 4]
for (index, element) in a.enumerated().reversed() {
if (element.isMultiple(of: 2)) {
a.remove(at: index)
}
}
А лучше использовать специальный метод коллекции, лаконичнее и быстрее:
a.removeAll(where: { $0.isMultiple(of: 2) })
Что происходит при итерации в прямом порядке:
Имеется массив [1, 2, 3, 4]
Проход по по массиву и удаление:
индекс: 0, элемент: 1, ничего не удалено
[1, 2, 3, 4]
индекс: 1, элемент: 2, удаление по индексу и сдвиг оставшейся части:
[1, 3, 4]
индекс: 2, элемент: 3, ничего не удалено:
[1, 3, 4]
индекс: 3, элемент: 4, попытка удаления, краш.
Что происходит после разворота:
Имеется массив [1, 2, 3, 4]
Проход по по массиву и удаление в обратном порядке и удаление с конца:
индекс: 3, элемент: 4, удаление:
[1, 2, 3]
индекс: 2, элемент: 3, ничего не удалено:
[1, 2, 3]
индекс: 1, элемент: 2, удаление:
[1, 3]
индекс: 0, элемент: 1, ничего не удалено:
[1, 3]