В Swift есть несколько способов отлавливать и диагностировать ошибки в коде:
Используется, если функция генерирует ошибку (
throws). enum LoginError: Error {
case wrongPassword
case userNotFound
}
func login(user: String, password: String) throws {
if user != "admin" { throw LoginError.userNotFound }
if password != "1234" { throw LoginError.wrongPassword }
}
do {
try login(user: "admin", password: "wrong")
} catch LoginError.wrongPassword {
print("Ошибка: Неверный пароль")
} catch {
print("Ошибка: \(error)")
}Эти функции прерывают выполнение программы, если что-то пошло не так.
assert() (только в Debug) let age = -5
assert(age >= 0, "Возраст не может быть отрицательным")
precondition() (работает в Release) precondition(age >= 0, "Возраст не может быть отрицательным")
fatalError() (прерывает программу) func getData() -> String {
fatalError("Метод ещё не реализован")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
– В несортированном массиве — O(n), так как приходится просматривать каждый элемент.
– В отсортированном массиве можно использовать бинарный поиск — O(log n), но только вручную или через методы binarySearch из алгоритмов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Приложения, написанные на Swift, могут быть довольно большими по размеру.
Swift — это относительно новый язык, и его стандартная библиотека не встроена в iOS (как, например, Objective-C runtime). Это значит, что при компиляции приложения в его бинарь включаются стандартные Swift-библиотеки.
При публикации в App Store, Xcode компилирует приложение для нескольких архитектур (arm64, armv7, x86_64). Это называется Fat Binary — один исполняемый файл включает версии для разных процессоров.
С версии Swift 5.0 ABI (Application Binary Interface) стабилизирован. Это означает, что в iOS 12.2+ уже есть встроенные Swift-библиотеки.
SwiftUI и Combine — новые технологии, они не так оптимизированы, как UIKit. При их использовании код разрастается за счёт декларативного подхода и дополнительной логики от Apple.
Если приложение использует локализацию, изображения, шрифты, CoreML, ARKit, это тоже увеличивает размер .ipa.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это называется Copy-on-Write (COW). Он работает так:
- Пока копия массива (или строки) не изменяется, они разделяют один и тот же блок памяти.
- При попытке модификации создаётся новая копия. Такой механизм экономит память и повышает производительность при передаче больших структур.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Stack (стек) – это структура данных, работающая по принципу LIFO (Last In, First Out – "последним пришел, первым ушел").
В Swift нет встроенного стека (кроме
Array), но можно создать свой:struct Stack<T> {
private var elements: [T] = []
mutating func push(_ item: T) {
elements.append(item)
}
mutating func pop() -> T? {
return elements.popLast() // Удаляет и возвращает верхний элемент
}
func peek() -> T? {
return elements.last // Возвращает верхний элемент без удаления
}
func isEmpty() -> Bool {
return elements.isEmpty
}
}
// Пример использования:
var stack = Stack<Int>()
stack.push(10)
stack.push(20)
stack.push(30)
print(stack.pop()!) // 30
print(stack.peek()!) // 20
print(stack.isEmpty()) // falseОбратный порядок выполнения (рекурсия) – стек вызовов функций.
Алгоритмы (обратная польская нотация, DFS – поиск в глубину)
История действий (назад-вперед в браузере, отмена в редакторе).
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Dependency Inversion Principle говорит, что модули высокого уровня не должны зависеть от модулей низкого уровня — они оба должны зависеть от абстракций. Это делается через протоколы и внедрение зависимостей.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
UIView всегда имеет CALayer, так как UIView — это обёртка над CALayer в UIKit. CALayer может существовать без UIView, потому что это низкоуровневый элемент Core Animation, который не зависит от UIKit. Каждый
UIView внутри себя содержит CALayer, который отвечает за отрисовку. let view = UIView()
print(view.layer) // Всегда существует!
CALayer можно создать и добавить в иерархию без UIView. let layer = CALayer()
layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor
if let window = UIApplication.shared.windows.first {
window.layer.addSublayer(layer) // Добавляем без UIView!
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Для отслеживания:
- Жестов и нажатий:
- UIGestureRecognizer (tap, long press, swipe).
- touchesBegan/ended — низкоуровневые события.
- Таймингов и задержек:
- CADisplayLink — вызов на каждом кадре (анимация).
- Timer.scheduledTimer — отложенное событие.
- DispatchQueue.main.asyncAfter — таймер через GCD.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
В Swift все типы данных делятся на два вида по семантике хранения и передачи:
Структуры (
struct), перечисления (enum) и кортежи (tuple) передаются по значению, то есть каждое присваивание создаёт копию объекта. struct User {
var name: String
}
var user1 = User(name: "Alice")
var user2 = user1 // Копия!
user2.name = "Bob"
print(user1.name) // "Alice" (НЕ изменилось)
print(user2.name) // "Bob"Классы (
class), акторы (actor) и замыкания (closure) передаются по ссылке, то есть несколько переменных могут ссылаться на один и тот же объект. class User {
var name: String
init(name: String) {
self.name = name
}
}
var user1 = User(name: "Alice")
var user2 = user1 // Передача ссылки!
user2.name = "Bob"
print(user1.name) // "Bob" (ИЗМЕНИЛОСЬ!)
print(user2.name) // "Bob"Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
– Сложность при большом количестве классов,
– Избыточное наследование,
– Низкая гибкость при изменении структуры,
– Возможные циклы зависимостей,
– Переусложнение при решении простых задач.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Память устройства можно представить в виде нескольких уровней, каждый из которых имеет свою скорость доступа, размер и назначение:
Это самая быстрая память, непосредственно встроенная в процессор. Регистры хранят те данные, с которыми процессор работает в данный момент времени.
Она находится непосредственно на процессоре или рядом с ним. Кэш-память используется для временного хранения копий часто используемых данных из основной памяти для ускорения доступа к ним. Кэш-память делится на несколько уровней (L1, L2, и иногда L3), где L1 — самый быстрый и обычно самый маленький.
Здесь хранятся данные и программы, с которыми компьютер работает в данный момент. Доступ к ОЗУ быстрый, но оно является временным хранилищем: при выключении устройства данные в ОЗУ теряются.
Это память для долговременного хранения данных. Она сохраняет информацию даже при выключении питания. HDD (жесткие диски) использовались ранее и работают на принципе магнитного записывания данных, в то время как SSD (твердотельные накопители) работают на основе флеш-памяти и обеспечивают более быстрый доступ к данным.
Это техника, которая позволяет операционной системе использовать часть жесткого диска (или SSD) как дополнительную оперативную память. Когда ОЗУ заполнено, операционная система может перемещать редко используемые данные из ОЗУ на диск в специальный файл подкачки (swap file), освобождая ОЗУ для других задач.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
1. Начинает с верхнего окна (UIWindow).
2. Рекурсивно спускается вниз по иерархии subviews, начиная с последней в списке (она визуально выше).
3. Проверяет:
- isHidden == false
- alpha > 0.01
- isUserInteractionEnabled == true
- point(inside:with:) == true
4. Если условия выполнены — эта вью становится responder’ом.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3
Принцип OCP (Open-Closed Principle) гласит:
"Программные сущности должны быть открыты для расширения, но закрыты для модификации."
Это значит, что код должен позволять добавлять новый функционал без изменения существующего кода.
Меньше багов – изменения не ломают старый код.
Лучшая поддержка – новый функционал добавляется без переписывания старого.
Гибкость – можно расширять систему без изменения её базовой логики.
Допустим, у нас есть класс, который рисует фигуры:
class ShapeDrawer {
func draw(shape: String) {
if shape == "circle" {
print("Рисуем круг")
} else if shape == "square" {
print("Рисуем квадрат")
}
}
}Лучше использовать наследование или протоколы, чтобы расширять функциональность, не меняя существующий код:
protocol Drawable {
func draw()
}
class Circle: Drawable {
func draw() {
print("Рисуем круг")
}
}
class Square: Drawable {
func draw() {
print("Рисуем квадрат")
}
}
class ShapeDrawer {
func draw(shape: Drawable) {
shape.draw()
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Классический deadlock
Если вызвать DispatchQueue.main.sync из UI-потока (main) — поток заблокируется сам на себе, вызывая мертвую блокировку. Такое случается при неправильной организации доступа к данным из UI.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В Swift словарь (`Dictionary<Key, Value>`) – это неупорядоченная коллекция пар `ключ → значение`, где ключи уникальны.
Swift позволяет сравнивать два словаря по их ключам и значениям, если и ключи, и значения соответствуют протоколу
Equatable. let dict1 = ["name": "Alice", "age": "25"]
let dict2 = ["name": "Alice", "age": "25"]
let dict3 = ["name": "Bob", "age": "30"]
print(dict1 == dict2) // ✅ true (значения одинаковые)
print(dict1 == dict3) // ❌ false (разные значения)
Ошибка при сравнении
Dictionary без EquatableЕсли значения не соответствуют `Equatable`, сравнение не сработает:
struct User {
let name: String
}
let dict1 = ["user": User(name: "Alice")]
let dict2 = ["user": User(name: "Alice")]
// Ошибка: Type 'User' does not conform to protocol 'Equatable'
// print(dict1 == dict2)Решение: Сделать
User Equatable:struct User: Equatable {
let name: String
}
print(dict1 == dict2) // Теперь работает!Можно сравнивать отдельные элементы по ключу.
let dict = ["name": "Alice", "age": "25"]
if dict["name"] == "Alice" {
print("Имя совпадает") // ✅
}
Можно сравнить только ключи или только значения.
let dict1 = ["name": "Alice", "age": "25"]
let dict2 = ["age": "30", "name": "Alice"]
print(dict1.keys == dict2.keys) // ✅ true (ключи одинаковые)
Сравнение значений
print(Set(dict1.values) == Set(dict2.values)) // ✅ true (если порядок неважен)
Если словарь хранит
Any, то прямое сравнение не сработает, и нужно сравнивать элементы вручную.let dict1: [String: Any] = ["name": "Alice", "age": 25]
let dict2: [String: Any] = ["name": "Alice", "age": 25]
// Функция сравнения словарей с `Any`
func areDictionariesEqual(_ dict1: [String: Any], _ dict2: [String: Any]) -> Bool {
return NSDictionary(dictionary: dict1).isEqual(to: dict2)
}
print(areDictionariesEqual(dict1, dict2)) // ✅ true
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Barriers (dispatch_barrier) в GCD основаны на последовательной синхронизации: они позволяют блокировать доступ к ресурсу и выполнять задачу эксклюзивно, прежде чем продолжится параллельное выполнение. Семафоры (DispatchSemaphore) — это счётчики, которые регулируют количество одновременно работающих потоков или доступ к ресурсу. Оба механизма основаны на примитивах синхронизации ядра.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM