LearningИзучите основы работы с массивами в Swift — от создания до полноценных операций над элементами в массиве.
Представьте, что вы ведете список покупок:
Список покупок:
1. 🥛 Молоко
2. 🍞 Хлеб
3. 🧀 Сыр
4. 🍎 Яблоки
В Swift такой список называется массивом. Это просто пронумерованный список, где у каждого элемента есть свой порядковый номер (индекс).
Массив может хранить элементы только ОДНОГО ТИПА. Нельзя смешивать строки и числа.
✅ Правильно:
let shoppingList = ["🥛", "🍞", "🧀"] // Только строки
let prices = [143, 68, 27] // Только числа
❌ Неправильно:
let mixed = ["🥛", 100, "🍞"] // Ошибка! Разные типы данных
Элементы хранятся в том порядке, в котором вы их добавили.
let fruits = ["🍎", "🍌", "🍊"]
print(fruits[0]) // Всегда будет "🍎" (первый)
print(fruits[1]) // Всегда будет "🍌" (второй)
🔄 Это отличает массивы от множеств (Set), где порядок не гарантируется.
В отличие от множеств (Set), массивы разрешают дубликаты.
let votes = [5, 5, 3, 5, 4, 5]
// Число 5 встречается 4 раза
print("Всего оценок: \(votes.count)") // 6
Первый элемент имеет индекс 0, второй — 1, и так далее.
let letters = ["A", "B", "C", "D"]
// Индексы: 0 1 2 3
letters[0] // "A" (первый)
letters[3] // "D" (четвертый)
// letters[4] // 💥 ОШИБКА! Индекс за пределами границ массива (Самая частая причина краша приложения)
⚠️ Запомните: первый элемент — всегда под индексом 0!
Всегда проверяйте, что индекс действительно существует!
let colors = ["красный", "зеленый", "синий"]
let index = 2
if index < colors.count {
print(colors[index]) // Этот код выполнится, только если индекс существует
} else {
print("Индекс \(index) вне диапазона. Допустимые индексы: 0...\(colors.count - 1)")
}
⚠️ Запомните: если вы обратитесь по индексу, которого нет в массиве – приложение упадёт
// Явно указываем тип
var emptyStrings: [String] = [] // Массив строк
var emptyNumbers: [Int] = [] // Массив чисел
// Swift УМНЫЙ — он сам понимает тип массива
let numbers = [1, 2, 3, 4, 5] // Swift понял: это [Int]
let names = ["Виктория", "Сергей"] // Swift понял: это [String]
// Можно указать тип явно (для ясности)
let explicitNumbers: [Int] = [1, 2, 3]
// var — массив можно изменять
var mutableArray = [1, 2, 3]
mutableArray.append(4) // ✅ Работает! [1, 2, 3, 4]
// let — массив НЕЛЬЗЯ менять
let immutableArray = [1, 2, 3]
immutableArray.append(4) // ❌ Ошибка! Нельзя изменить
🔑 Золотое правило:
let= “После создания, изменить уже не сможем абсолютно никак”var= “После создания, можем изменить”
var students = ["Павел", "Иблантий"]
print(students) // ["Павел", "Иблантий"]
// Добавляем элемент в КОНЕЦ массива
students.append("Мария") // ["Павел", "Иблантий", "Мария"]
// Добавляем на конкретное МЕСТО (по индексу)
students.insert("Денис", at: 1) // ["Павел", "Денис", "Иблантий", "Мария"]
// Добавляем СРАЗУ НЕСКОЛЬКО элементов
let newStudents = ["Галина", "Фёдор"]
students.append(contentsOf: newStudents) // ["Павел", "Денис", "Иблантий", "Мария", "Галина", "Фёдор"]
📝 Запомните:
append= добавляет элемент в конец массиваinsert(at:)= добавляет элемент по указанному индексуappend(contentsOf:)= обавляет несколько элементов в конец массива
let colors = ["🔴 Красный", "🟢 Зеленый", "🔵 Синий"]
let firstColor = colors[0] // "🔴 Красный"
let secondColor = colors[1] // "🟢 Зеленый"
let thirdColor = colors[2] // "🔵 Синий"
// ⚠️ Crash!
// let fourthColor = colors[3] // 💥 ПРОГРАММА УПАДЕТ! (Такого индекса не существует)
// first и last безопасны — они возвращают Optional
if let first = colors.first {
print("Первый цвет: \(first)")
} else {
print("Массив пуст!")
}
if let last = colors.last {
print("Последний цвет: \(last)")
}
🛡️ Правило безопасности: Всегда проверяйте, существует ли индекс, или используйте
.first/.last
var grades = [4, 5, 3, 5]
// Меняем конкретный элемент
grades[2] = 4 // Заменяем тройку на четверку
// Стало – [4, 5, 4, 5]
⚠️ Важно: При изменении убедитесь, что индекс существует!
var playlist = ["Песня 1", "Песня 2", "Песня 3", "Песня 4"]
print("Плейлист: \(playlist)")
// Удаляем по индексу
let removedSong = playlist.remove(at: 1) // "Песня 2"
print("Удалили: \(removedSong)")
print("Осталось: \(playlist)") // ["Песня 1", "Песня 3", "Песня 4"]
// Удаляем первый и последний
playlist.removeFirst() // Удаляем "Песня 1"
playlist.removeLast() // Удаляем "Песня 4"
print("После удаления краев: \(playlist)") // ["Песня 3"]
// Удаляем ВСЁ!
playlist.removeAll()
let fruits = ["🍎 яблоко", "🍌 банан", "🍊 апельсин", "🍎 яблоко"]
// Проверяем, есть ли элемент
let hasApple = fruits.contains("🍎 яблоко") // true
let hasGrape = fruits.contains("🍇 виноград") // false
// Ищем ИНДЕКС элемента
if let index = fruits.firstIndex(of: "🍌 банан") {
print("Банан найден на позиции \(index)") // 1
}
// Ищем ПЕРВЫЙ элемент, подходящий под условие
let numbers = [10, 23, 45, 67, 89]
// Найти первое четное число
if let firstEven = numbers.first(where: { number in
number % 2 == 0
}) {
print("Первое четное: \(firstEven)") // 10
}
// Найти индекс первого числа больше 50
if let index = numbers.firstIndex(where: { number in
number > 50
}) {
print("Первое число >50 имеет индекс \(index)") // 3 (число 67)
}
var unsorted = [3, 1, 4, 2]
// Сортируем внутри массива (меняем оригинал)
unsorted.sort() // [1, 2, 3, 4]
// Сортируем копию массива (оригинал не трогаем)
let original = [3, 1, 4, 2]
let sorted = original.sorted()
print("Оригинал: \(original)") // [3, 1, 4, 2] (не изменился!)
print("Копия: \(sorted)") // [1, 2, 3, 4]
🔑 Запомните:
sort()= меняет оригиналsorted()= создает копию
let array = [1, 2, 3, 4, 5]
array.isEmpty // false (массив не пустой)
array.count // 5 (количество элементов в массиве)
array.first // Optional(1) (первый элемент)
array.last // Optional(5) (последний элемент)
Представьте, что мы пишем приложение для школы. У нас есть:
struct Student {
let name: String
let scores: [Int] // Оценки ученика
}
struct Teacher {
let name: String
let subject: String // Предмет, который ведет
let salary: Int // Зарплата
}
struct Director {
let name: String
let experience: Int // Опыт
}
Как хранить их ВСЕХ в одном списке, если они разных типов?
Протокол — это как контракт. Если структура подписывает протокол, она ОБЯЗАНА выполнить его требования.
/// Протокол, объединяющий всех людей в школе
protocol Person {
var name: String { get }
var surname: String { get set }
}
📖 Расшифровка:
{ get }— свойство можно только читать (let){ get set }— свойство можно и читать, и изменять (var)
struct Student: Person {
let name: String
var surname: String
let scores: [Int]
}
struct Teacher: Person {
let name: String
var surname: String
let subject: String
let salary: Int
}
struct Director: Person {
let name: String
var surname: String
let experience: Int
}
// Тип массива — [Person], но внутри могут быть любые типы данных, которые подписались под протокол Person
let schoolMembers: [Person] = [
Student(name: "Павел", surname: "Петров", scores: [5, 4, 5]),
Teacher(name: "Василиса", surname: "Иванова", subject: "Математика", salary: 50_000),
Student(name: "Милена", surname: "Сидорова", scores: [4, 4, 5]),
Director(name: "Ангелина", surname: "Михайловна", experience: 15)
]
print("В школе \(schoolMembers.count) человек")
// Проходим по всем
for person in schoolMembers {
// У всех есть имя и фамилия (из протокола)
print("👤 \(person.name) \(person.surname)")
// Чтобы получить доступ к УНИКАЛЬНЫМ свойствам,
// нужно "привести (скастить)" к конкретному типу
if let student = person as? Student {
print(" 📚 Ученик, оценки: \(student.scores)")
} else if let teacher = person as? Teacher {
print(" 🍎 Учитель, предмет: \(teacher.subject)")
} else if let director = person as? Director {
print(" 👔 Директор, опыт: \(director.experience) лет")
}
}
// Найдем директора с опытом 15 лет
if let directorIndex = schoolMembers.firstIndex(where: { person in
// Проверяем, является ли человек директором и имеет ли опыт работы 15 лет
if let director = person as? Director {
if director.experience == 15 {
return true
}
}
// Если так и не нашли нужного человека
return false
}) {
print("Нашли директора по индексу \(directorIndex)")
// Меняем данные (нужен var т.к. собираемся изменить директора)
if var director = schoolMembers[directorIndex] as? Director {
director.experience = 16
// Важно понимать, что созданный нами director – это лишь копия существующего в массиве
// Нам обязательно нужно обновить того директора, который так и остался без изменений в массиве
schoolMembers[directorIndex] = director // Обновляем в массиве
print("Опыт увеличен до \(director.experience)")
}
}
Какой индекс у первого элемента массива?
Что произойдет при вызове array[10], если в массиве 5 элементов?
В чем разница между sort() и sorted()?
sort() меняет массив, sorted() создает новыйsort() для чисел, sorted() для строкМожно ли хранить в одном массиве Student и Teather ?
| Действие | Код | Пояснение |
|---|---|---|
| Создать пустой массив | var array: [Int] = [] |
Пустой массив чисел |
| С данными | let array = [1, 2, 3] |
Массив из трех чисел |
| Добавить в конец | array.append(4) |
Добавляет 4 в конец |
| Вставить по индексу | array.insert(10, at: 0) |
Вставляет 10 в начало |
| Получить элемент | let item = array[2] |
Берём элемент с индексом 2 |
| Удалить | array.remove(at: 1) |
Удаляет элемент с индексом 1 |
| Проверить наличие | array.contains(5) |
true, если есть 5 |
| Найти индекс | array.firstIndex(of: 3) |
Индекс числа 3 |
| Отсортировать | array.sorted() |
Возвращает сортированную копию |
| Количество | array.count |
Сколько элементов |
| Проверить пустоту | array.isEmpty |
true, если пусто |
let array = [10, 20, 30]
let first = array[1] // ❌ Думают, что это первый элемент, но это ВТОРОЙ!
let correct = array[0] // ✅ Правильно: первый элемент
let array = [1, 2, 3]
let element = array[5] // 💥 Программа упадет!
// ✅ Надо проверить:
if array.count > 5 {
let element = array[5]
}
let array = [1, 2, 3]
array.append(4) // ❌ Ошибка! let = неизменяемый
// ✅ Надо использовать var:
var mutableArray = [1, 2, 3]
mutableArray.append(4) // ✅ Работает!
Поздравляю! Вы освоили массивы — фундаментальную структуру данных. Теперь вы готовы к изучению:
| Тема | Описание |
|---|---|
| Множества (Sets) | Как массивы, но без порядка и без повторов |
| Словари (Dictionaries) | Хранят пары “ключ-значение” |