Можно реализовать кэш:
- Через обычный словарь или мапу (ключ — запрос, значение — ответ).
- Устанавливать ограничение по времени жизни (например, TTL) и вручную очищать старые значения.
- Добавлять механизм проверки валидности (по дате, флагу, внешнему событию).
- Использовать структуры с ограничением размера, удаляя наименее используемые элементы (например, LRU).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Барьер (Barrier) – это механизм синхронизации потоков, который позволяет контролировать порядок выполнения операций** в многопоточной среде.
Используются в многопоточном программировании для управления порядком операций с памятью.
В многопоточной среде процессоры и компиляторы могут оптимизировать порядок команд, что может привести к непредсказуемому поведению. Барьеры памяти предотвращают это.
#include <stdatomic.h>
atomic_int sharedValue = 0;
void updateValue() {
atomic_store_explicit(&sharedValue, 10, memory_order_release);
}
void readValue() {
int value = atomic_load_explicit(&sharedValue, memory_order_acquire);
}
Используются в Grand Central Dispatch (GCD)** для контроля порядка выполнения задач в
DispatchQueue. - Позволяет блокировать очередь на время выполнения задачи.
- Все задачи до барьера выполняются параллельно.
- Барьер ждёт завершения всех предыдущих задач, выполняется эксклюзивно, затем разрешает следующие задачи.
let queue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
queue.async {
print("Задача 1")
}
queue.async {
print("Задача 2")
}
// БАРЬЕРНАЯ ОПЕРАЦИЯ
queue.async(flags: .barrier) {
print("🔴 Барьер: все предыдущие задачи завершены, выполняюсь один!")
}
queue.async {
print("Задача 3")
}
В OpenMP (
#pragma omp barrier) ждёт завершения всех потоков перед выполнением следующего кода. #pragma omp parallel
{
printf("До барьера\n");
#pragma omp barrier
printf("После барьера\n");
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Для value-типов очистка памяти происходит при выходе за область видимости. Для ссылочных — важно отслеживать retain cycles и использовать weak/unowned. Можно реализовать протокол CacheClearable с методом очистки, а ключи кэшировать в словарях с NSCache, который автоматически очищает содержимое при нехватке памяти.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Подписку на уведомления (
NotificationCenter), KVO или Combine в жизненном цикле UIViewController лучше размещать в методах, где гарантируется её актуальность и корректное удаление. Подписка на события обычно происходит в `viewDidLoad()`, так как этот метод вызывается один раз при создании контроллера.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification),
name: .someNotification,
object: nil
)
}
@objc func handleNotification(_ notification: Notification) {
print("Получено уведомление")
}Если подписка должна работать только когда экран на экране, используем
viewWillAppear().var cancellable: AnyCancellable?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
cancellable = NotificationCenter.default.publisher(for: .someNotification)
.sink { _ in
print("Событие получено")
}
}
Когда контроллер скрывается, подписки можно удалить, чтобы избежать ненужных вызовов.
Удаление подписки на
NotificationCenter:override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .someNotification, object: nil)
}Удаление
Combine подписки (cancellable)override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
cancellable?.cancel()
cancellable = nil
}Если подписка работает на протяжении всего жизненного цикла контроллера, её можно удалить в `deinit`.
deinit {
NotificationCenter.default.removeObserver(self)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Коллекции Swift:
- Типизированные — Array<Int>, Set<String>, Dictionary<String, Int>.
- Итерабельные, поддерживают for-in, map, filter, reduce.
- Безопасные по индексу — доступ за границами вызывает crash.
- Имеют value semantics — при копировании создаются независимые копии (если не оптимизировано через COW).
Swift также предоставляет lazy, stride, enumerated, zip, prefix, что делает работу с коллекциями очень выразительной и безопасной.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS и macOS приложениях, разработанных с использованием Swift или Objective-C,
UIView и CALayer играют ключевые роли в управлении и отображении пользовательского интерфейса. Несмотря на то, что они тесно связаны, между ними есть важные различия. Давайте рассмотрим их подробнее.UIView — это базовый класс для всех элементов пользовательского интерфейса в iOS. Он представляет собой прямоугольную область на экране, которая может отображать контент и реагировать на события пользователя, такие как нажатия, жесты и касания.UIView предоставляет множество свойств и методов для управления внешним видом, положением и поведением представления. Примеры включают frame, bounds, center, backgroundColor, alpha, isHidden, и subviews. UIView также поддерживает анимации, автолэйаут и работу с событийной системой.UIView обрабатывает пользовательские события, такие как касания и жесты. Он предоставляет методы, такие как touchesBegan, touchesMoved, и touchesEnded, для обработки этих событий.let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myView.backgroundColor = .blue
view.addSubview(myView)
CALayer — это базовый класс для всех графических слоев, используемых в Core Animation. Он обеспечивает низкоуровневую поддержку для рендеринга, анимации и композиции графики.CALayer предоставляет свойства для управления внешним видом, такими как backgroundColor, borderWidth, cornerRadius, shadowOpacity, contents (для отображения изображений), и transform. CALayer также поддерживает анимации, используя ключевые кадры и основные анимации. CALayer не обрабатывает пользовательские события напрямую. Эти задачи оставлены на UIView, который может содержать один или несколько слоев.let myLayer = CALayer()
myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myLayer.backgroundColor = UIColor.blue.cgColor
view.layer.addSublayer(myLayer)
UIView — это более высокий уровень абстракции, предназначенный для работы с пользовательским интерфейсом и обработкой событий. CALayer — более низкоуровневый элемент, который фокусируется на рендеринге и анимации графики.UIView обрабатывает события пользовательского интерфейса. CALayer не обрабатывает события, но предоставляет возможности для рендеринга и анимации.UIView может содержать другие представления (subviews) и управлять их иерархией. CALayer может содержать другие слои (sublayers) и управлять их иерархией.UIView использует UIView.animate для создания анимаций, которые высокоуровневые и просты в использовании. CALayer использует CAAnimation и его подклассы для создания анимаций, которые более гибкие и мощные, но требуют большего количества кода.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
При активации bounce-эффекта (перетягивания) в UIScrollView, когда пользователь тянет содержимое за границы:
- Меняется bounds.origin — она уходит за пределы contentOffset.
- Это происходит во время резкого скролла, обновлений или pull-to-refresh.
После отпускания — origin возвращается в нормальные границы с анимацией.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
Отделённый слайс массива в большинстве языков (например, в Python, Swift) будет того же типа, что и оригинальный массив. Однако в зависимости от языка — это может быть новая копия или представление (view) на те же данные.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В языке 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
С iOS 17 используется
Чтобы сделать класс наблюдаемым, достаточно:
- Отметить его как
- Использовать обычные свойства, без
- SwiftUI будет автоматически отслеживать изменения и обновлять интерфейс.
Это заменяет необходимость в
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Каждый способ создания макетов (layout'а) в iOS-разработке имеет свои преимущества и недостатки.
Удобный графический интерфейс для быстрой настройки и визуального просмотра изменений.
Простая настройка ограничений (constraints) для адаптивного интерфейса.
Возможность быстрого создания и изменения макетов без написания кода.
Ограниченные возможности для создания сложных и динамических макетов.
Трудности при слиянии изменений в storyboard или xib файлах в больших командах.
Более медленное время загрузки по сравнению с программными подходами.
Поддержка различных устройств и ориентаций экрана.
Возможность создания сложных и адаптивных макетов с помощью ограничений.
Упрощенная настройка ограничений через визуальный интерфейс.
Может быть сложно освоить, особенно для новичков.
Требует тщательного планирования и может стать сложным при работе с большим количеством ограничений.
Возможность точной настройки макета с помощью кода.
Легкость создания динамических и условных макетов.
Легче управлять изменениями в коде по сравнению с визуальными файлами.
Требует больше времени и усилий для настройки, особенно для сложных макетов.
Отсутствие визуального редактора может затруднить представление конечного результата.
Легкость создания и управления сложными макетами с минимальными усилиями.
Автоматическое управление ограничениями для вложенных элементов.
Поддержка различных ориентаций и размеров экранов.
Менее гибкие по сравнению с чистым Auto Layout или программными подходами.
Не всегда подходят для всех типов макетов, особенно для более сложных компоновок.
Простота и понятность кода благодаря декларативному подходу.
Мгновенное обновление интерфейса при изменении кода.
Современные возможности языка и тесная интеграция с экосистемой Apple.
Поддержка различных платформ (iOS, macOS, watchOS, tvOS).
Поддержка только iOS 13 и выше, что может ограничить использование на старых устройствах.
Некоторые функции еще находятся в стадии разработки, и могут быть ограничены возможности по сравнению с UIKit.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
RunLoop работает только на потоках, где он был явно создан. У каждой main queue и кастомного потока может быть свой RunLoop. Фоновым очередям в GCD RunLoop не нужен по умолчанию, пока не используется таймер или input source.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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
- ARC работает сразу, как только счётчик = 0 (детерминированное управление);
- GC (в Java, Python) работает фоново, периодически сканируя объекты. Он может задерживать удаление, но справляется с циклами ссылок. ARC не умеет разрывать retain cycle — нужно вручную применять weak.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift (и во многих других языках программирования) по умолчанию числовой литерал с плавающей запятой интерпретируется как `Double`, а не
Float. Double имеет 64 бита, а Float – 32 бита. Это значит, что Double может хранить более точные значения, что особенно важно при математических вычислениях.Большинство API и стандартных библиотек Swift (например,
sin(), cos(), pow()) работают именно с Double. Например:
let x = 3.14 // По умолчанию это Double
let y = sin(x) // sin() принимает Double
На современных 64-битных процессорах операции с
Double выполняются так же быстро или даже быстрее, чем с Float, из-за оптимизаций в аппаратном обеспечении.Float может округлять числа с потерей точности, что может привести к неожиданным результатам. Пример ошибки округления в
Float:let a: Float = 0.1 + 0.2
print(a == 0.3) // false 😱
Если всё же нужен
Float, надо указать это явно:let number: Float = 3.14
или
let number = 3.14 as Float
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Принцип абстракции и обобщения. Дженерики позволяют создавать универсальные и типобезопасные компоненты, не дублируя код для каждого типа.
Также они поддерживают принцип повторного использования и инкапсуляцию логики.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS существует несколько способов вёрстки пользовательского интерфейса. Каждый из них имеет свои плюсы и минусы в зависимости от проекта.
Используется: визуальный редактор в Xcode.
Storyboard
- Позволяет создавать весь UI в одном файле
.storyboard.- Поддерживает Auto Layout и Size Classes для адаптивного дизайна.
- Можно настраивать Segue (переходы между экранами).
Используется: Полностью программная вёрстка без использования Interface Builder.
let button = UIButton()
button.setTitle("Нажми", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
Используется: Современный способ верстки с декларативным синтаксисом.
struct ContentView: View {
var body: some View {
VStack {
Text("Привет, SwiftUI!")
.font(.largeTitle)
Button("Нажми меня") {
print("Кнопка нажата")
}
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Witness table — механизм Swift для протоколов, в ней хранится соответствие реализаций протокольным методам.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это абстрактная структура данных, работающая по принципу LIFO (Last In, First Out), что означает "последний пришёл — первый вышел". Это значит, что последний добавленный элемент будет первым при извлечении из стека. Под капотом реализации стека могут быть разные, и они зависят от конкретного языка программирования и задач, которые необходимо решить.
Один из самых распространённых способов реализации стека — это использование массива. В такой реализации элементы стека хранятся в массиве, и индекс последнего элемента (вершина стека) отслеживается отдельной переменной.
struct Stack<Element> {
private var storage: [Element] = []
mutating func push(_ element: Element) {
storage.append(element)
}
mutating func pop() -> Element? {
return storage.popLast()
}
func peek() -> Element? {
return storage.last
}
var isEmpty: Bool {
return storage.isEmpty
}
}Стек можно реализовать с использованием связных списков, где каждый элемент списка содержит данные и ссылку на следующий элемент в стеке. Вершина стека в такой реализации — это начало связного списка.
class Node<Element> {
var value: Element
var next: Node?
init(value: Element) {
self.value = value
}
}
struct Stack<Element> {
private var head: Node<Element>?
mutating func push(_ element: Element) {
let node = Node(value: element)
node.next = head
head = node
}
mutating func pop() -> Element? {
let node = head
head = head?.next
return node?.value
}
func peek() -> Element? {
return head?.value
}
var isEmpty: Bool {
return head == nil
}
}Это системный стек, который используется во время выполнения программы для хранения информации о вызовах функций/методов. Он хранит адреса возврата, параметры функций, локальные переменные и другие данные, необходимые для управления вызовами функций и их возврата.
Обратную польскую нотацию для вычисления арифметических выражений. Управление вызовами функций в программном стеке. Поддержка операций undo в приложениях.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Pod — это библиотека или фреймворк, подключаемый через CocoaPods, менеджер зависимостей в iOS. Он автоматически загружает, компилирует и подключает сторонние библиотеки к проекту.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1