1. Это механизм синхронизации, который ограничивает доступ к ресурсу только одному потоку в определённый момент времени.
2. Он блокирует другие потоки до завершения работы текущего.
3. Используется для предотвращения race condition при работе с общими данными.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Это высокоуровневый механизм синхронизации, который объединяет взаимное исключение (mutex) и условные переменные (condition variables) для управления доступом к объектам в многопоточной среде.
Только один поток может выполнить защищенный блок кода в любой момент времени.
Позволяют потокам ожидать определенных условий, а другим потокам уведомлять их о наступлении этих условий.
class ThreadSafeClass {
private var internalState = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")
func increment() {
queue.sync {
internalState += 1
}
}
func getState() -> Int {
return queue.sync {
internalState
}
}
}С
NSLockclass ThreadSafeClass {
private var internalState = 0
private let lock = NSLock()
func increment() {
lock.lock()
internalState += 1
lock.unlock()
}
func getState() -> Int {
lock.lock()
let state = internalState
lock.unlock()
return state
}
}С
objc_sync_enter и objc_sync_exitclass ThreadSafeClass: NSObject {
private var internalState = 0
func increment() {
objc_sync_enter(self)
internalState += 1
objc_sync_exit(self)
}
func getState() -> Int {
objc_sync_enter(self)
let state = internalState
objc_sync_exit(self)
return state
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Через менеджеры зависимостей:
- CocoaPods, Carthage, Swift Package Manager — позволяют подключать внешние библиотеки, управлять их версиями, следить за обновлениями. Также возможна ручная интеграция, но она менее гибкая и масштабируемая.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
– Int, Double, String, Bool — базовые типы,
– struct, class, enum, tuple,
– Optional,
– Protocol,
– Function,
– Any, AnyObject, Never.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS жизненный цикл
UIViewController определяет последовательность вызовов методов, происходящих во время создания, отображения, скрытия и уничтожения контроллера. На этом этапе создаётся экземпляр
UIViewController, но его view ещё не загружено. - Можно переопределить
init() или init(coder:), если контроллер создаётся из Storyboard. - Можно передавать данные через инициализатор.
class MyViewController: UIViewController {
var titleText: String
init(titleText: String) {
self.titleText = titleText
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}Когда контроллеру нужно отобразить свой
view, вызывается loadView() (если представление создаётся программно) и viewDidLoad() (если загружается из Storyboard или XIB). loadView() – создаёт view программно (обычно не переопределяется). viewDidLoad() – вызывается один раз после загрузки view. override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
print("viewDidLoad - View загружено в память")
}Когда
UIViewController добавляется в иерархию UIWindow и становится видимым, вызываются следующие методы: viewWillAppear(_:) – вызывается перед появлением на экране. viewDidAppear(_:) – вызывается после появления на экране. viewWillDisappear(_:) – вызывается перед скрытием. viewDidDisappear(_:) – вызывается после скрытия. override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear - View скоро появится на экране")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear - View уже на экране")
}Когда
UIViewController больше не нужен, вызывается deinit(), а его view может быть выгружено с вызовом viewDidUnload() (но сейчас это редко используется). deinit {
print("deinit - Контроллер удалён из памяти")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Это механизм публикации и подписки на события в iOS.
- Позволяет компонентам приложения обмениваться данными без прямых ссылок.
- Работает по принципу наблюдателя: объект отправляет уведомление, а подписчики получают его.
- Используется для глобального взаимодействия между модулями (например, обновление UI после фоновой загрузки данных).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это сообщения, которые отправляются приложением пользователю даже тогда, когда само приложение не активно. Это эффективный способ удержания пользователей и предоставления им важной информации.
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения push-уведомлений. Для этого приложение отправляет запрос к Apple Push Notification Service (APNs) с запросом на получение уникального токена устройства (device token).
APNs генерирует уникальный токен для устройства и отправляет его обратно приложению. Приложение затем передает этот токен на свой сервер.
Когда необходимо отправить push-уведомление, сервер приложения формирует сообщение, включающее содержимое уведомления и токен устройства, и отправляет его на APNs.
APNs принимает сообщение от сервера, определяет устройство по токену и отправляет уведомление на это устройство.
Когда устройство получает уведомление, операционная система отображает его пользователю. Если пользователь взаимодействует с уведомлением, приложение может выполнить определенные действия, такие как открытие конкретного экрана.
В AppDelegate
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Запрос разрешения на отправку уведомлений
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Преобразуем токен в строку
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
// Отправляем токен на сервер
// serverAPI.registerDeviceToken(token)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Set хранит уникальные элементы без порядка, а Dictionary — пары ключ-значение, где ключи уникальны. Set быстрее для операций проверки принадлежности и поиска. Dictionary удобен для поиска по ключу и хранения дополнительных данных для каждого ключа.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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
👍3
Можно создать структуру, которая будет использовать массивы пар ключ-значение, хэш-функции или реализовать собственную логику поиска, вставки и удаления. Это потребует понимания базовых алгоритмов хэширования.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2
Принцип 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
👍1
Memory Graph в Xcode показывает живые объекты и их связи. Это полезно для поиска retain cycles, обнаружения неосвобождённых контроллеров и анализа структуры объектов. Доступен во время отладки через Debug Navigator.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift ключи в словаре (
Dictionary) должны быть уникальными и сравниваться между собой. Поэтому, если вы хотите использовать*свою структуру в качестве ключа, она должна соответствовать протоколу Hashable. Структура должна соответствовать
Hashable Должен быть реализован
hash(into:) или использовать Equatable + Hashable автоматически Свойства структуры должны быть
Hashable (если String, Int, Double – все ок) struct Person: Hashable {
let id: Int
let name: String
}
// Теперь можно использовать `Person` как ключ
var peopleAges: [Person: Int] = [
Person(id: 1, name: "Alice"): 25,
Person(id: 2, name: "Bob"): 30
]
// Доступ по ключу
let alice = Person(id: 1, name: "Alice")
print(peopleAges[alice] ?? "Не найдено") // 25Если нужно кастомное хеширование, можно реализовать
hash(into:):struct Person: Hashable {
let id: Int
let name: String
func hash(into hasher: inout Hasher) {
hasher.combine(id) // Используем только id для хеша
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Свойства "Content Hugging Priority" и "Content Compression Resistance Priority" играют ключевую роль в системе Auto Layout. Эти свойства помогают определить, как вьюшки (views) должны быть отформатированы и как они реагируют на изменения в доступном пространстве в интерфейсе пользователя. Рассмотрим подробнее, что означает каждое из этих свойств и как они используются в разработке интерфейсов.
Определяет, насколько сильно вьюшка должна "обнимать" своё содержимое. Это свойство указывает на желательность вьюшки быть как можно ближе к своим внутренним размерам, основанным на своем содержимом.
Определяет, насколько сильно вьюшка должна противостоять сжатию размеров меньше, чем размеры её содержимого.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Task priority — это указание уровня важности задачи, которое система может учитывать при распределении ресурсов. Приоритет не гарантирует порядок, но даёт подсказку планировщику, какие задачи предпочтительнее обрабатывать первыми. В Swift есть уровни приоритетов (например, high, low, utility и другие).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Утечка памяти (
memory leak) – это ситуация, когда память остаётся выделенной, но больше не используется программой и не освобождается. class Person {
var pet: Pet?
deinit { print("Person удалён") }
}
class Pet {
var owner: Person?
deinit { print("Pet удалён") }
}
var person: Person? = Person()
var pet: Pet? = Pet()
person?.pet = pet
pet?.owner = person
person = nil
pet = nilСлабые (
weak) или безвладельческие (unowned) ссылки не увеличивают счётчик ссылок, что разрывает цикл.class Person {
var pet: Pet?
deinit { print("Person удалён") }
}
class Pet {
weak var owner: Person? // Слабая ссылка
deinit { print("Pet удалён") }
}
var person: Person? = Person()
var pet: Pet? = Pet()
person?.pet = pet
pet?.owner = person
person = nil // "Person удалён"
pet = nil // "Pet удалён"unowned похож на weak, но он не может быть `nil`.class Owner {
var car: Car?
deinit { print("Owner удалён") }
}
class Car {
unowned var owner: Owner // Безвладельческая ссылка
init(owner: Owner) { self.owner = owner }
deinit { print("Car удалён") }
}
var owner: Owner? = Owner()
owner?.car = Car(owner: owner!)
owner = nil // "Owner удалён", "Car удалён"Замыкания захватывают объекты, создавая циклические ссылки.
Проблема:
self удерживается замыканиемclass ViewController {
var closure: (() -> Void)?
func setup() {
closure = {
print(self) // Удерживает self, создавая цикл!
}
}
deinit { print("ViewController удалён") }
}
var vc: ViewController? = ViewController()
vc?.setup()
vc = nil // ❌ "ViewController" НЕ удалится- Открываем
Xcode > Product > Profile. - Выбираем
Leaks. - Запускаем приложение и проверяем, остаются ли объекты в памяти.
Если метод
deinit не вызывается – значит, объект утёк в память.class Test {
deinit { print("Test удалён") }
}
var obj: Test? = Test()
obj = nil // Должно напечатать "Test удалён"- В Xcode открываем "Debug Memory Graph" (нажимая значок в Debugger).
- Смотрим, какие объекты остались в памяти.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Ключ должен соответствовать протоколу Hashable. Это необходимо, чтобы можно было быстро сравнивать и размещать ключи в хэш-таблице словаря.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
UserDefaults — это хранилище для сохранения простых данных (строки, числа, массивы). Но если нужно сохранить сложные объекты, их сначала кодируют в `Data` (Codable), а затем сохраняют. Для примитивных типов (строки, числа, массивы, словари)
UserDefaults работает без кодирования:let defaults = UserDefaults.standard
// Сохранение
defaults.set("Иван", forKey: "username")
defaults.set(25, forKey: "age")
// Чтение
let name = defaults.string(forKey: "username") ?? "Нет имени"
let age = defaults.integer(forKey: "age")
print(name, age) // Иван 25
Если нужно сохранить свой объект, сначала его нужно закодировать в
Data.struct User: Codable {
let name: String
let age: Int
}Сохранение в
UserDefaultslet user = User(name: "Иван", age: 25)
let defaults = UserDefaults.standard
if let encoded = try? JSONEncoder().encode(user) {
defaults.set(encoded, forKey: "user")
}
Загрузка из
UserDefaultsif let savedData = defaults.data(forKey: "user"),
let savedUser = try? JSONDecoder().decode(User.self, from: savedData) {
print(savedUser.name, savedUser.age) // Иван 25
}
Чтобы удалить ключ:
defaults.removeObject(forKey: "user")
Можно сохранить массив объектов, просто закодировав его:
let users = [
User(name: "Иван", age: 25),
User(name: "Анна", age: 30)
]
if let encoded = try? JSONEncoder().encode(users) {
defaults.set(encoded, forKey: "users")
}
// Читаем массив обратно
if let savedData = defaults.data(forKey: "users"),
let savedUsers = try? JSONDecoder().decode([User].self, from: savedData) {
print(savedUsers) // [{name: Иван, age: 25}, {name: Анна, age: 30}]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5