Это высокоуровневый механизм синхронизации, который объединяет взаимное исключение (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
  Один из самых простых и гибких способов реализовать абстракцию — это использование протоколов (protocols).
Протоколы определяют набор требований (свойств, методов), не реализуя их, и позволяют легко заменять конкретные реализации в коде. Это даёт возможность:
- Заменять реализацию (например, для тестирования).
- Разделять ответственность.
- Поддерживать слабую связность компонентов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Это механизм в iOS и macOS для обмена сообщениями между различными частями приложения. Он позволяет объектам отправлять и получать уведомления без необходимости напрямую ссылаться друг на друга, что способствует более гибкому и модульному дизайну.
Любой объект может отправить уведомление с помощью Notification Center. Уведомления идентифицируются по имени (
Notification.Name). Можно передать дополнительную информацию в виде словаря (userInfo).NotificationCenter.default.post(name: .myNotification, object: nil)
Объекты могут регистрироваться для получения уведомлений с определенным именем. Для обработки уведомлений используется метод, который будет вызван при получении уведомления.
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: .myNotification, object: nil)
@objc func handleNotification(notification: Notification) {
print("Received notification")
}
Важно удалять наблюдателей, когда они больше не нужны, чтобы избежать утечек памяти. Обычно это делается в методе
deinit или перед уничтожением объекта.NotificationCenter.default.removeObserver(self, name: .myNotification, object: nil)
Объекты не нужно напрямую ссылаться друг на друга, что улучшает модульность кода.
Позволяет легко организовать обмен сообщениями между различными частями приложения.
Уведомления могут использоваться многими объектами, что облегчает реализацию функций, таких как обновление интерфейса или реагирование на события.
Когда данные изменяются, можно отправить уведомление для обновления пользовательского интерфейса.
NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
Например, можно подписаться на уведомление о смене состояния сети.
NotificationCenter.default.addObserver(self, selector: #selector(handleNetworkChange), name: .reachabilityChanged, object: nil)
Различные модули приложения могут общаться друг с другом через Notification Center, не создавая сильных зависимостей.
NotificationCenter.default.post(name: .userDidLogin, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: .userDidLogin, object: nil)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  👍1
  Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Если вы хотите задать отступы (margins, padding) для
UIView в жизненном цикле UIViewController, то важно выбрать правильный момент, когда размеры view уже определены.  class MyViewController: UIViewController {
    let myView = UIView()
    override func viewDidLoad() {
        super.viewDidLoad()
        myView.backgroundColor = .red
        view.addSubview(myView)
    }
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        // Установка отступов (margins)
        myView.frame = view.bounds.insetBy(dx: 20, dy: 50)
    }
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Они определяют, насколько элемент предпочитает сохранять свой минимальный размер. Чем выше значение, тем меньше вероятность, что элемент растянется больше, чем необходимо его контенту.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Слабые ссылки (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
  – Обычный public класс может использоваться в другом модуле, но не может быть унаследован.
– open класс можно наследовать и переопределять даже в других модулях.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Если все переменные в коде сделать
weak, объекты могут мгновенно удаляться из памяти, потому что никто не будет владеть ими (strong reference).  -
weak создает слабую ссылку – объект не увеличивает счетчик ссылок (retain count).  - Если нет других (strong) ссылок на объект, он удаляется (ARC освобождает память).
-
weak переменные всегда являются Optional, потому что объект может стать nil в любой момент.  class Person {
    weak var name: String? // ❌ Ошибка! Строки – это value type, weak нельзя
}Проблема, если
weak используется вездеclass Car {
    weak var model: String? // ❌ Ошибка (value type)
    weak var owner: Person? // ⚠️ Будет nil, если нет других strong ссылок
}
class Person {
    var car: Car?
}
var person: Person? = Person()
person?.car = Car()
person?.car?.owner = person // ❌ `owner` - weak, объект сразу удалится
print(person?.car?.owner) // nil, объект Person уничтоженНапример, между
delegate и ViewController   protocol SomeDelegate: AnyObject {
       func doSomething()
   }
   class ViewController {
       weak var delegate: SomeDelegate? // ✅ Prevent retain cycle
   }Например, ячейки в
UITableView не должны владеть ViewController.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  1. Удобен для координации задач, выполняемых параллельно.
2. Используется для уведомления, когда все задачи завершены.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
  Даже если циклы не вложены, общая временная сложность функции зависит от количества операций. Если два цикла идут последовательно по одному и тому же массиву, сложность будет O(n + n) = O(n). А если по разным — и их размеры разные — то, например, O(n + m).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
  👍1
  Fetched Property — это динамическая связь, основанная на предопределённом запросе (fetch request). В отличие от обычных связей (relationship), она:
- не кешируется;
- выполняет отдельный запрос каждый раз при доступе;
- может фильтровать или выбирать связанные объекты по более сложным правилам.
Это полезно в случаях, когда нужно получить связанные данные по определённым условиям, но нужно учитывать, что производительность ниже, чем у обычной связи.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  В
Operation (ранее NSOperation) в Foundation есть встроенный механизм отмены, который позволяет корректно завершить операцию, если она больше не нужна. Однако отмена не прерывает выполнение автоматически – код внутри операции должен сам проверять флаг отмены и корректно завершаться.  Вызывается
cancel() – операция помечается как отмененная.  Флаг
isCancelled становится true, но операция продолжает выполняться, если не проверяет этот флаг.  Операция должна самостоятельно проверять
isCancelled и прерываться.  class MyOperation: Operation {
    override func main() {
        for i in 1...10 {
            if isCancelled { return }  // Проверяем, отменена ли операция
            print("Выполняется шаг \(i)")
            sleep(1) // Симуляция работы
        }
    }
}
let queue = OperationQueue()
let operation = MyOperation()
queue.addOperation(operation)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    operation.cancel()  // Отменяем через 3 секунды
}Если операция асинхронная (
isAsynchronous = true), просто проверять isCancelled недостаточно. Надо корректно управлять состояниями (isExecuting, isFinished).class AsyncOperation: Operation {
    private var _executing = false
    private var _finished = false
    
    override var isAsynchronous: Bool { true }
    
    override var isExecuting: Bool {
        get { return _executing }
        set {
            willChangeValue(for: \.isExecuting)
            _executing = newValue
            didChangeValue(for: \.isExecuting)
        }
    }
    override var isFinished: Bool {
        get { return _finished }
        set {
            willChangeValue(for: \.isFinished)
            _finished = newValue
            didChangeValue(for: \.isFinished)
        }
    }
    override func start() {
        if isCancelled {
            isFinished = true
            return
        }
        
        isExecuting = true
        executeTask()
    }
    private func executeTask() {
        DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
            if self.isCancelled {
                self.complete()
                return
            }
            print("Асинхронная операция завершена")
            self.complete()
        }
    }
    private func complete() {
        isExecuting = false
        isFinished = true
    }
}
let queue = OperationQueue()
let asyncOp = AsyncOperation()
queue.addOperation(asyncOp)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    asyncOp.cancel()  // Отменяем через 1 секунду
}Если у вас есть зависимости между операциями, отмена одной может автоматически отменить все последующие:
let op1 = MyOperation()
let op2 = MyOperation()
op2.addDependency(op1)
let queue = OperationQueue()
queue.addOperations([op1, op2], waitUntilFinished: false)
// Отменяем первую операцию, вторая тоже не выполнится
op1.cancel()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  👍1
  При компиляции в Swift класс проходит несколько стадий обработки:
Анализ синтаксиса и семантики – компилятор проверяет код на ошибки.
Генерация промежуточного представления (IR) – создаётся код на уровне LLVM IR.
Оптимизация – Swift применяет различные оптимизации, например, inlining, dead code elimination и другие.
Генерация машинного кода – итоговый код превращается в исполняемый машинный код, специфичный для платформы.
В отличие от структур, классы в Swift являются ссылочными типами и хранятся в куче (heap). Это означает, что:
- При создании объекта выделяется память в куче.
- Swift автоматически использует ARC (Automatic Reference Counting) для управления памятью.
- Методы класса могут вызываться через виртуальную таблицу (vtable), если класс использует динамическую диспетчеризацию.
- Если класс final, компилятор может оптимизировать вызовы методов, убрав динамическую диспетчеризацию.
- Наследование делает вызовы методов менее предсказуемыми (они идут через vtable).
- В отличие от структур, классы не копируются при передаче в функцию, а передаётся ссылка.
class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
    func speak() {
        print("Some sound")
    }
}
final class Dog: Animal {
    override func speak() {
        print("Woof!")
    }
}
let myDog = Dog(name: "Buddy")
myDog.speak()Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Apple рекомендует использовать значимые типы (например, struct, enum) по следующим причинам:
- Они более предсказуемы, потому что копируются при передаче, и изменения в одной копии не затрагивают другие.
- Это упрощает многопоточность и предотвращает гонки данных.
- Swift делает копирование структур эффективным благодаря Copy-On-Write.
- Для UI и моделей данных это снижает количество неожиданных побочных эффектов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её.
Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами.
Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие.
Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения.
Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова
final. Если метод, свойство или индексатор объявлен как final, то он не может быть переопределён в подклассе.class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // Этот метод будет переопределен в подклассах, если необходимо
    }
}
class Bicycle: Vehicle {
    var hasBasket = false
}
class Car: Vehicle {
    var gear = 1
    final func drive() {
        print("Car is moving")
    }
    override func makeNoise() {
        print("Vroom!")
    }
}Подклассы могут вызывать методы своего суперкласса с помощью ключевого слова
super. Это позволяет подклассам расширять, а не заменять поведение суперкласса.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Регулярное участие в собеседованиях (раз в полгода-год) помогает:
- держать навыки общения в тонусе;
- понимать ожидания рынка;
- адекватно оценивать свою стоимость;
- быть готовым к внезапным изменениям в работе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM
  💊6
  В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций.
Когда один объект (например,
ViewController) зависит от другого (NetworkManager), первый становится клиентом, а второй – зависимостью.  class NetworkManager {
    func fetchData() {
        print("Данные загружены")
    }
}
class ViewController {
    let networkManager: NetworkManager
    
    init(networkManager: NetworkManager) {
        self.networkManager = networkManager
    }
    
    func loadData() {
        networkManager.fetchData()
    }
}Жесткие зависимости можно ослабить, используя протоколы.
protocol NetworkService {
    func fetchData()
}
class NetworkManager: NetworkService {
    func fetchData() {
        print("Данные загружены")
    }
}
class ViewController {
    let networkService: NetworkService
    
    init(networkService: NetworkService) {
        self.networkService = networkService
    }
    
    func loadData() {
        networkService.fetchData()
    }
}В MVVM зависимость между
ViewController и ViewModel.  В VIPER модули зависят друг от друга, но слабо связаны через протоколы.
В DI (Dependency Injection) зависимости передаются снаружи, что повышает тестируемость и гибкость.
Чтобы управлять внешними зависимостями (библиотеками), используются
Swift Package Manager (SPM)
CocoaPods
Carthage
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
    VIEW IN TELEGRAM