– Протоколы — только набор требований, не содержат реализации состояния.
Swift не поддерживает полноценные абстрактные классы, поэтому протоколы часто используются вместо них.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
автоматизированная разработка ПО.
непрерывная разработка приложений.
развёртывание облачных приложений.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊5
Ключевое слово open позволяет классу быть доступным и наследуемым за пределами модуля. Это максимальный уровень доступа и расширяемости в Swift.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊7
В iOS существует несколько ленивых (
lazy) контейнеров и вью, которые откладывают создание или загрузку элементов до момента их фактического использования. Обычное свойство инициализируется сразу, а
lazy – только при первом вызове. class Example {
lazy var expensiveObject: Data = {
print("Объект создан!")
return Data()
}()
}
let obj = Example()
print("Объект ещё не создан")
_ = obj.expensiveObject // Только теперь создастсяЕсли вы хотите избежать лишних вычислений, можно использовать ленивую последовательность:
let numbers = (1...1000).lazy.map { $0 * 2 } // Не вычисляется сразу!
print(numbers.first!) // Только теперь вычисляется первый элементВ отличие от обычных
VStack и HStack, ленивые версии создают элементы только при прокрутке.ScrollView {
LazyVStack {
ForEach(0..<1000) { index in
Text("Элемент \(index)")
}
}
}Они работают по принципу переиспользования ячеек, загружая их только когда нужно.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Строка \(indexPath.row)"
return cell
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Элементы массива (Array) в Swift (и других языках) хранятся в непрерывном участке памяти:
- Все значения идут друг за другом — это позволяет быстро получать элементы по индексу (O(1)).
- При увеличении размера массива может происходить перевыделение памяти, чтобы вместить больше элементов.
- В Swift Array — структура с копированием по необходимости (copy-on-write), что делает работу с массивами эффективной и безопасной.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
В языке Swift нет встроенного оператора
future, но если речь идет о концепции Future из асинхронного программирования, то давай разберемся, зачем она нужна и как используется.Future (или Promise в некоторых реализациях) — это объект, который представляет значение, которое станет доступным в будущем после завершения асинхронной операции. Это удобно, когда нужно работать с кодом, который выполняется не мгновенноЗапросы в сеть (API)
Чтение файлов
Долгие вычисления
В Swift
Future чаще всего используется в рамках Combine.В Combine есть структура
Future, которая позволяет создать асинхронную операцию и подписаться на ее результат:import Combine
// Функция, которая возвращает Future
func fetchData() -> Future<String, Error> {
return Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
let success = Bool.random() // Симулируем успех или ошибку
if success {
promise(.success("Данные загружены!"))
} else {
promise(.failure(NSError(domain: "Ошибка загрузки", code: -1, userInfo: nil)))
}
}
}
}
// Используем Future
let future = fetchData()
let cancellable = future.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Завершено без ошибок")
case .failure(let error):
print("Ошибка: \(error.localizedDescription)")
}
}, receiveValue: { value in
print("Получены данные: \(value)")
})
Когда нужна одноразовая асинхронная операция (например, запрос в сеть)
Когда используешь Combine и хочешь обернуть асинхронный код в реактивный стиль
Если в будущем планируешь объединять несколько асинхронных операций (композиция
Future)Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Capture list используется в замыканиях Swift, чтобы управлять тем, как значения захватываются: как weak, unowned или strong. Это предотвращает retain cycle и утечки.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Слабые ссылки (weak references) играют важную роль в управлении памятью, особенно когда нужно предотвратить циклы сильных ссылок (retain cycles) и утечки памяти.
Циклы сильных ссылок возникают, когда два объекта держат сильные ссылки друг на друга, что препятствует их освобождению из памяти. Слабые ссылки разрывают этот цикл, позволяя одному из объектов освобождаться.
class Person {
var name: String
weak var friend: Person?
init(name: String) {
self.name = name
}
}
var alice: Person? = Person(name: "Alice")
var bob: Person? = Person(name: "Bob")
alice?.friend = bob
bob?.friend = alice
alice = nil // Теперь объекты могут быть освобождены
bob = nil Утечки памяти происходят, когда объекты, которые больше не нужны, не освобождаются из памяти. Слабые ссылки помогают избежать этих утечек, обеспечивая правильное освобождение памяти. Делегаты часто объявляются как слабые ссылки, чтобы избежать утечек памяти.
protocol TaskDelegate: AnyObject {
func taskDidFinish()
}
class Task {
weak var delegate: TaskDelegate?
func complete() {
delegate?.taskDidFinish()
}
}
class ViewController: TaskDelegate {
var task = Task()
init() {
task.delegate = self
}
func taskDidFinish() {
print("Task finished")
}
} Слабые ссылки удобны для временных зависимостей, когда объект не должен удерживаться в памяти, если нет других сильных ссылок. Использование слабых ссылок для временных объектов.
class Cache {
weak var temporaryObject: SomeClass?
}
class SomeClass {
// Код класса
}
var cache = Cache()
var object = SomeClass()
cache.temporaryObject = object
object = SomeClass() // Старый объект удаляется, так как на него нет сильных ссылок Основное преимущество слабых ссылок заключается в их способности разрывать циклы ссылок, предотвращая утечки памяти.
Слабые ссылки позволяют объектам освобождаться из памяти, когда на них больше нет сильных ссылок, что улучшает управление ресурсами.
Использование слабых ссылок обеспечивает более гибкое и безопасное управление зависимостями между объектами.
Необходимо учитывать, что слабые ссылки могут стать nil в любой момент, поэтому требуется дополнительная проверка.
Требуется хорошее понимание жизненного цикла объектов и управления памятью, чтобы правильно использовать слабые ссылки.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это расширение для iOS-приложений, которое позволяет модифицировать push-уведомления до их показа. Например, можно добавить изображение, вложение или изменить текст перед отображением пользователю.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Фреймы (frames) в iOS-разработке используются для задания размеров и расположения элементов интерфейса (UIView) вручную.
Когда нужно анимировать движение элемента, проще всего работать с его
frame, так как он напрямую управляет origin (координаты) и size (размеры). UIView.animate(withDuration: 0.5) {
self.button.frame.origin.x += 100
}Если вы не используете Auto Layout или хотите задать положение элементов программно,
frame позволяет точно указать размеры и координаты. let button = UIButton(type: .system)
button.frame = CGRect(x: 50, y: 100, width: 200, height: 50)
button.setTitle("Нажми меня", for: .normal)
view.addSubview(button)
При динамической подгрузке ячеек в
UITableView или UICollectionView можно вручную вычислять frame для ускорения работы, вместо использования Auto Layout, который может замедлить скроллинг.При рисовании или настройке слоев
CALayer используется frame, чтобы точно определить размеры слоя. let borderLayer = CALayer()
borderLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
borderLayer.borderWidth = 2
borderLayer.borderColor = UIColor.red.cgColor
view.layer.addSublayer(borderLayer)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В большинстве языков — float, double, или Float32, Float64:
- float — 32 бита, ограниченная точность.
- double — 64 бита, выше точность и диапазон. Python использует тип float, который реализован как 64-битный IEEE 754 double.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Словарь (Dictionary) представляет собой коллекцию пар ключ-значение, где каждый ключ должен быть уникальным. Чтобы использовать какой-либо тип в качестве ключа словаря, этот тип должен соответствовать протоколу
Hashable. Это требование обусловлено тем, что Swift использует хеш-таблицу для хранения элементов словаря, что обеспечивает быстрый доступ к его элементам.Должны быть уникальными: Каждый ключ в словаре должен быть уникальным. При попытке добавить в словарь элемент с ключом, который уже существует в словаре, старое значение будет заменено на новое.
Должны соответствовать протоколу
Hashable: Это означает, что тип ключа должен иметь способность быть правильно хешированным. Большинство базовых типов Swift (например, String, Int, Double и др.) уже соответствуют Hashable, поэтому их можно использовать в качестве ключей без дополнительных усилий.Могут быть любого типа: Значения в словаре могут быть любого типа, и они не обязаны соответствовать протоколу Hashable.
Могут повторяться: Разные ключи могут иметь одинаковые значения.
var personAge: [String: Int] = ["John": 30, "Sara": 25]
Вы также можете использовать собственные пользовательские типы в качестве ключей словаря, но для этого ваш тип должен соответствовать протоколу
Hashable. Это включает в себя реализацию требуемых методов для сравнения на равенство (==) и хеширования (hash(into:)).struct Person: Hashable {
var name: String
var id: Int
}
var peopleDictionary: [Person: String] = [Person(name: "John", id: 1): "Engineer"]Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
- unowned — это слабая ссылка, но с гарантией, что объект ещё существует во время обращения. Если объект уже освобождён — произойдёт крах (crash).
- unowned(unsafe) — ещё менее безопасный вариант, не делает проверку на nil вообще. Это низкоуровневая, "сырой" доступ к памяти, использовать его нужно крайне осторожно.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
@autoclosure — это специальный атрибут в Swift, который автоматически превращает переданное выражение в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится. @autoclosure?Обычно его используют для улучшения читаемости кода, особенно когда нужно лениво вычислять аргумент функции. Например, если переданный аргумент — это сложное вычисление, его выполнение можно отложить до нужного момента.
Допустим, у нас есть функция, которая принимает замыкание
func logMessage(_ message: () -> String) {
print("Лог: \(message())")
}
// Вызываем функцию, передавая замыкание
logMessage { "Сообщение: \(2 + 2)" }
Теперь используем `@autoc чтобы сделать вызов функции проще
func logMessage(_ message: @autoclosure () -> String) {
print("Лог: \(message())")
}
// Теперь аргумент можно передавать без {}
logMessage("Сообщение: \(2 + 2)")
Стандартные функции Swift используют @autoclosure, чтобы избежать вычисления аргументов, если проверка не нужна:assert(2 + 2 == 4, "Ошибка: 2 + 2 не равно 4!")
Допустим, у нас есть функция, которая выполняет блок только если включен режим отладкие в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится.
Обычно его используют для улучшения читаемости кода, особенно когда нужно.`@autoc но если нужно сохранить замыкание для будущего выполнения, это можно сделать рый автоматически превращает переданное выражение в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится.
Обычно его используют для улучшения читаемости кода, особенно когда нужно лениво вычислять аргумент функции.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
2. Включает выделение памяти и назначение значений свойствам (вручную или по умолчанию).
3. В Kotlin инициализация может выполняться через первичный конструктор, блоки init или вторичные конструкторы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊8
В Swift нет множественного наследования классов, но можно использовать множественное наследование через протоколы.
Swift запрещает множественное наследование классов, потому что оно может привести к конфликтам и алмазной проблеме (diamond problem).
Допустим, в языке с поддержкой множественного наследования у нас есть два родительских класса с одинаковым методом:
class A {
public:
void greet() { cout << "Hello from A"; }
};
class B {
public:
void greet() { cout << "Hello from B"; }
};
// C наследуется от A и B
class C : public A, public B {};
C obj;
obj.greet(); // Какой метод вызвать? A или B?В Swift можно реализовать множественное наследование через протоколы, поскольку класс может соответствовать нескольким протоколам одновременно.
protocol Flyable {
func fly()
}
protocol Swimmable {
func swim()
}
class Animal {}
class Duck: Animal, Flyable, Swimmable {
func fly() {
print("Утка летит")
}
func swim() {
print("Утка плывёт")
}
}
let duck = Duck()
duck.fly() // Утка летит
duck.swim() // Утка плывётЕсли хочется, чтобы протокол предоставлял реализацию по умолчанию (почти как родительский класс), можно использовать
extension:protocol Walker {
func walk()
}
extension Walker {
func walk() {
print("Иду вперёд")
}
}
class Person: Walker {}
let human = Person()
human.walk() // "Иду вперёд" (метод взят из extension)Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Пассивная модель — это подход, при котором объект модели не знает о существовании интерфейса (view) и не уведомляет его об изменениях. Контроллер сам запрашивает обновление данных и обновляет интерфейс вручную.
Активная модель — модель сама уведомляет представление или контроллер об изменениях, обычно через делегаты, нотификации или биндинги. Это повышает реактивность, но усложняет структуру.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
В 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
Closure захватывает value type по значению. То есть создаётся копия значения, и она остаётся доступной внутри замыкания, даже если оригинальное значение вышло из области видимости.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Метод `hitTest(_:with:)` в
UIView используется для определения, какая вью была нажата пользователем. Он ищет самый глубокий (верхний) UI-элемент, который должен обработать касание. Если у
UIView выключено свойство isUserInteractionEnabled, то hitTest(_:with:) не будет работать – вью полностью игнорирует касания. let button = UIButton()
button.isUserInteractionEnabled = false
let touchPoint = CGPoint(x: 50, y: 50)
let result = button.hitTest(touchPoint, with: nil)
print(result) // nil ❌
Если
UIView почти полностью прозрачна (alpha меньше 0.01), то она не будет участвовать в обработке событий.let view = UIView()
view.alpha = 0.005
let touchPoint = CGPoint(x: 50, y: 50)
let result = view.hitTest(touchPoint, with: nil)
print(result) // nil ❌
Если вью скрыта (
isHidden = true), hitTest(_:with:) не сработает, так как iOS её вообще не обрабатываетlet view = UIView()
view.isHidden = true
let touchPoint = CGPoint(x: 50, y: 50)
let result = view.hitTest(touchPoint, with: nil)
print(result) // nil ❌
hitTest(_:with:) проверяет только внутри `bounds` вью, и если точка находится за пределами, он вернёт `nil`.let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let touchPoint = CGPoint(x: 150, y: 150) // Вне границ вью
let result = view.hitTest(touchPoint, with: nil)
print(result) // nil ❌
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3💊2