Swift | Вопросы собесов
2.13K subscribers
28 photos
955 links
Download Telegram
🤔 Расскажи про механизм отмены в operatsion

В Operation (ранее NSOperation) в Foundation есть встроенный механизм отмены, который позволяет корректно завершить операцию, если она больше не нужна. Однако отмена не прерывает выполнение автоматически – код внутри операции должен сам проверять флаг отмены и корректно завершаться.

🚩Как работает отмена `Operation`?

Вызывается 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
👍1
🤔 Чем опасна команда PO?

Команда PO в LLDB (print object) вызывает метод объекта, чтобы отобразить его состояние. Если метод содержит побочные эффекты или ошибки, это может привести к изменению состояния объекта во время отладки. Это особенно опасно при отладке сложных объектов с логикой.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Расскажи про букву D в solid

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит:
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

🚩Плохой пример (Нарушение DIP)

class MySQLDatabase {
func fetchData() -> String {
return "Данные из MySQL"
}
}

class DataManager {
let database = MySQLDatabase() // Прямая зависимость от MySQL

func getData() -> String {
return database.fetchData()
}
}


🚩Хороший пример (Используем DIP)

Вводим абстракцию (Протокол)
protocol Database {
func fetchData() -> String
}


Реализуем конкретные базы данных
class MySQLDatabase: Database {
func fetchData() -> String {
return "Данные из MySQL"
}
}

class PostgreSQLDatabase: Database {
func fetchData() -> String {
return "Данные из PostgreSQL"
}
}


Используем абстракцию в DataManager
class DataManager {
private let database: Database // Зависимость от абстракции

init(database: Database) {
self.database = database
}

func getData() -> String {
return database.fetchData()
}
}


Использование
let mySQLDataManager = DataManager(database: MySQLDatabase())
print(mySQLDataManager.getData()) // "Данные из MySQL"

let postgreSQLDataManager = DataManager(database: PostgreSQLDatabase())
print(postgreSQLDataManager.getData()) // "Данные из PostgreSQL"


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
🤔 Что такое IRC?

Это механизм управления памятью в Swift, который отслеживает количество ссылок на объект. Объект удаляется из памяти, когда счётчик ссылок достигает нуля. Этот подход обеспечивает эффективное управление ресурсами, но требует осторожности с циклическими ссылками.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11👀101🤔1🤯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
👍2
🤔 Когда использовать dictionary?

Это структура данных, которая хранит пары ключ-значение. Его стоит использовать, если:
- Требуется быстрый доступ по ключу (O(1) для поиска)
- Неважен порядок элементов
- Ключи уникальны (словарь не допускает дубликатов ключей)
- Нужно легко изменять данные (добавление/удаление за O(1))


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Расскажи про классы

Классы — это ссылочные типы в Swift, которые позволяют создавать объекты с общими свойствами и методами. Они поддерживают наследование, работают с ARC (Automatic Reference Counting) и хранятся в куче (heap).

🚩Основные характеристики классов

🟠Ссылочный тип
Когда вы присваиваете класс другой переменной, копируется не сам объект, а ссылка на него. Изменения, сделанные через одну ссылку, затронут и другие.

🟠Хранятся в куче
В отличие от структур, которые хранятся в стеке, классы создают объекты в куче. Это позволяет передавать объекты между функциями без копирования.

🟠Automatic Reference Counting (ARC)
Swift использует ARC для управления памятью. Объект удаляется из памяти, когда на него больше нет ссылок.

🟠Наследование
В отличие от структур, классы могут наследовать свойства и методы от других классов. Поддерживают переопределение методов (override).

🟠Идентичность объектов
Два объекта класса можно сравнивать по ссылке (===), а не только по значению (==).

class Animal {
var name: String

init(name: String) {
self.name = name
}

func speak() {
print("Some sound")
}
}

class Dog: Animal {
override func speak() {
print("Woof!")
}
}

let dog1 = Dog(name: "Buddy")
let dog2 = dog1 // Копируется ссылка, а не объект

dog2.name = "Charlie"

print(dog1.name) // "Charlie", так как dog1 и dog2 указывают на один объект


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Когда использовать массивы?

Это упорядоченные коллекции элементов. Они полезны, когда:
- Нужно сохранить порядок элементов
- Требуется итерация по элементам (O(n) при линейном обходе)
- Часто добавляются элементы в конец (O(1))
- Хранится набор однотипных данных (например, список чисел)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Расскажи жизненный цикл vue контроллера

В iOS жизненный цикл UIViewController определяет последовательность вызовов методов, происходящих во время создания, отображения, скрытия и уничтожения контроллера.

🚩Подробное объяснение стадий

🟠Создание (Initialization)
На этом этапе создаётся экземпляр 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 (Loading)
Когда контроллеру нужно отобразить свой view, вызывается loadView() (если представление создаётся программно) и viewDidLoad() (если загружается из Storyboard или XIB).
loadView() – создаёт view программно (обычно не переопределяется).
viewDidLoad() – вызывается один раз после загрузки view.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
print("viewDidLoad - View загружено в память")
}


🟠Отображение на экране (Appearing & Disappearing)
Когда 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 уже на экране")
}


🟠Удаление из памяти (Deallocation)
Когда UIViewController больше не нужен, вызывается deinit(), а его view может быть выгружено с вызовом viewDidUnload() (но сейчас это редко используется).
deinit {
print("deinit - Контроллер удалён из памяти")
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
4😁2🤯1
🤔 Что известно про хеш-таблицы (hash tables)?

Это структура данных, которая использует хеш-функцию для быстрого поиска, вставки и удаления.
Основные особенности:
- Поиск за O(1) в среднем
- Использует массив и хеш-функцию
- Коллизии решаются разными методами (цепочки, открытая адресация)
- Неупорядоченная структура


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какие есть варианты обезопасить работу с историей images?

Обеспечение безопасности работы с историей изображений в iOS-приложениях может включать несколько уровней защиты:

🟠Контроль доступа к изображениям
- Используйте Privacy Settings (NSPhotoLibraryUsageDescription, NSCameraUsageDescription) для контроля доступа к фотоальбому.
- Для ограниченного доступа в iOS 14+ используйте PHPickerViewController.
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
if status == .authorized {
// Доступ есть
} else {
// Запросить разрешение
PHPhotoLibrary.requestAuthorization { newStatus in
if newStatus == .authorized {
print("Доступ получен")
}
}
}


🟠Шифрование изображений
- Если изображения сохраняются локально, используйте AES-шифрование.
- Можно хранить ключ в Keychain или использовать Secure Enclave.
import CommonCrypto

func encryptImage(data: Data, key: Data) -> Data? {
var buffer = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0

let status = CCCrypt(
CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding), key.bytes, key.count,
nil, data.bytes, data.count, &buffer, buffer.count, &numBytesEncrypted
)

return status == kCCSuccess ? buffer.prefix(numBytesEncrypted) : nil
}


🟠Безопасное хранение изображений
Core Data с Encrypted Store – можно использовать зашифрованные базы данных, такие как SQLCipher.
FileManager + Data Protection – файлы можно хранить в Application Support с флагом .completeFileProtection.
Keychain – если нужно хранить ссылки на изображения или ключи.
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("secure_image.jpg")
try? imageData.write(to: fileURL, options: .completeFileProtection)


🟠Ограничение кеширования изображений
- Если изображение чувствительное, отключите кеширование в URLSession:
let config = URLSessionConfiguration.default
config.urlCache = nil // Отключаем кеш
let session = URLSession(configuration: config)


🟠Защита от утечек в памяти
- Убедитесь, что ссылки на изображения не создают retain cycle.
- Используйте weak ссылки в кэше изображений.
class ImageCache {
private let cache = NSCache<NSString, UIImage>()

func store(image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}

func retrieve(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
}


🟠Безопасная загрузка изображений (защита от MITM)
- Используйте HTTPS вместо HTTP.
- Включите App Transport Security (ATS) в Info.plist.
- Верифицируйте SSL-сертификаты при загрузке.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if let serverTrust = challenge.protectionSpace.serverTrust {
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Чем отличается MVM от MVP?

MVP (Model-View-Presenter) – архитектурный паттерн, где Presenter управляет View.
- View – отображает данные
- Presenter – получает данные из Model и передает в View
- Model – источник данных
MVM (Model-View-Model) – используется в SwiftUI и Jetpack Compose, где ViewModel отделяет бизнес-логику от UI.
- View – интерфейс
- ViewModel – управляет состоянием
- Model – данные
Разница: в MVP Presenter напрямую управляет View, а в MVM ViewModel только передает данные, а View сама решает, как их отображать.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔9👍2
🤔 Какие проблемы можно получить , если оставить контекст?

Если оставить контекст в замыкании, не принимая во внимание возможные проблемы, это может привести к нескольким серьезным проблемам, особенно в многопоточном и асинхронном программировании.

🚩Проблемы

🟠Утечки памяти (Retain Cycles)
Одной из самых распространенных проблем является утечка памяти из-за циклов удержания (retain cycles). Это происходит, когда два или более объекта удерживают ссылки друг на друга, препятствуя освобождению памяти. В этом примере closure захватывает self, что создает цикл удержания: MyClass держит сильную ссылку на closure, а closure держит сильную ссылку на self.
class MyClass {
var value: Int = 0
var closure: (() -> Void)?

func setupClosure() {
closure = {
self.value += 1
}
}
}

let instance = MyClass()
instance.setupClosure()


🟠Непредсказуемое поведение и условия гонки (Race Conditions)
Когда замыкания захватывают изменяемый контекст, это может привести к условиям гонки и непредсказуемому поведению, особенно при работе в многопоточном окружении. Если метод increment вызывается из разных потоков, это может привести к условиям гонки и некорректному изменению значения count.
class Counter {
var count = 0

func increment() {
DispatchQueue.global().async {
self.count += 1
}
}
}

let counter = Counter()
counter.increment()


🟠Задержки в освобождении ресурсов
Если замыкания захватывают тяжелые ресурсы (например, файлы, сети), это может привести к задержкам в их освобождении, что может негативно сказаться на производительности приложения. Если FileHandler освобождается, но замыкание все еще захватывает file, это может привести к задержке в освобождении файлового дескриптора.
class FileHandler {
var file: File?

func processFile() {
DispatchQueue.global().async {
self.file?.read()
}
}
}


🟠Потеря захваченных данных
Когда используется слабая ссылка (weak), замыкание может обнаружить, что захваченный объект освобожден, что приводит к тому, что слабая ссылка становится nil. Это требует дополнительных проверок и обработки.
class MyClass {
var value: Int = 0
var closure: (() -> Void)?

func setupClosure() {
closure = { [weak self] in
guard let strongSelf = self else { return }
strongSelf.value += 1
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Когда появляется Sitable?

Это состояние интерфейса, в котором пользовательский ввод не вызывает изменений, но при этом интерфейс остается активным.
Используется в UI/UX для предотвращения некорректного поведения интерфейса, например:
- Во время загрузки данных
- В процессе валидации формы
- При временной блокировке кнопок


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
🤔 Как работают push нотификации?

Это сообщения, которые отправляются приложением пользователю даже тогда, когда само приложение не активно. Это эффективный способ удержания пользователей и предоставления им важной информации.

🚩Как работают push-уведомления

1⃣Регистрация устройства
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения push-уведомлений. Для этого приложение отправляет запрос к Apple Push Notification Service (APNs) с запросом на получение уникального токена устройства (device token).

2⃣Получение токена устройства
APNs генерирует уникальный токен для устройства и отправляет его обратно приложению. Приложение затем передает этот токен на свой сервер.

3⃣Отправка уведомления на сервер
Когда необходимо отправить push-уведомление, сервер приложения формирует сообщение, включающее содержимое уведомления и токен устройства, и отправляет его на APNs.

4⃣Доставка уведомления
APNs принимает сообщение от сервера, определяет устройство по токену и отправляет уведомление на это устройство.

5⃣Получение уведомления на устройстве
Когда устройство получает уведомление, операционная система отображает его пользователю. Если пользователь взаимодействует с уведомлением, приложение может выполнить определенные действия, такие как открытие конкретного экрана.

🚩Пример кода для регистрации устройства

В 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
🤔 Какие есть типы ссылок?

Ссылки определяют управление памятью и временем жизни объектов. Основные типы:
1. Сильная (strong reference) – объект остается в памяти, пока на него есть ссылка
2. Слабая (weak reference) – не предотвращает сборку мусора
3. Небезопасная (unowned) – слабая ссылка без автоматического обнуления
4. Циклические ссылки (strong reference cycles) – могут приводить к утечкам памяти


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁2
🤔 Как устроено наследование?

Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её.

🚩Основы наследования

🟠Определение базового класса
Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами.

🟠Создание подкласса
Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие.

🟠Переопределение методов и свойств
Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения.

🟠Предотвращение переопределения
Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова 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

Подклассы могут вызывать методы своего суперкласса с помощью ключевого слова super. Это позволяет подклассам расширять, а не заменять поведение суперкласса.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие способы layout'а есть?

Это способ размещения элементов в интерфейсе. Основные варианты:
1. Absolute Layout – жесткое позиционирование элементов
2. Relative Layout – элементы позиционируются относительно друг друга
3. Linear Layout – элементы располагаются по одной оси
4. Grid Layout – элементы располагаются в сетке
5. Constraint Layout – гибкое размещение с ограничениями (используется в Android)
6. Flexbox/Grid (CSS) – адаптивная верстка в веб-разработке


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
🤔 Надо ли отслеживать статус задачи в dispatchworkitem?

Да, отслеживание статуса задачи в DispatchWorkItem может быть полезным, но это зависит от требований приложения.

🟠Когда это полезно?
Если задача может быть отменена (cancel())
Если выполнение задачи можно приостановить или продолжить
Если нужно проверить завершение перед выполнением следующего действия*
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Запускаем задачу
DispatchQueue.global().async(execute: workItem)

// Отмена перед выполнением
workItem.cancel()

// Проверяем статус выполнения
if workItem.isCancelled {
print("Задача отменена")
} else {
print("Задача выполнена")
}


🟠Можно ли проверить, завершена ли задача?
В DispatchWorkItem нет метода проверки завершения.
Но можно вручную отслеживать завершение с помощью notify:
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Сообщаем о завершении
workItem.notify(queue: .main) {
print("Задача завершена")
}

DispatchQueue.global().async(execute: workItem)


🟠Надо ли всегда отслеживать статус?
Если задача короткая и простая → НЕ ОБЯЗАТЕЛЬНО.
Если задача важная, может быть отменена или зависит от других задач → ЛУЧШЕ ОТСЛЕЖИВАТЬ.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие плюсы и минусы layout'а?

Layout определяет расположение элементов на экране, его выбор влияет на производительность и удобство поддержки кода.
Плюсы:
- Гибкость – позволяет адаптировать UI под разные размеры экранов.
- Читаемость кода – декларативные подходы (например, Flexbox, ConstraintLayout) упрощают понимание.
- Адаптивность – некоторые виды layout автоматически подстраиваются под содержимое.
- Кроссплатформенность – разметка может быть использована на разных устройствах.
Минусы:
- Производительность – сложные иерархии могут замедлять рендеринг.
- Сложность отладки – в сложных layout'ах трудно понять, почему элемент занимает именно такое место.
- Ограниченность возможностей – некоторые системы layout могут не поддерживать желаемые анимации и трансформации.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что означает принцип open closed?

Принцип OCP (Open-Closed Principle) гласит:
"Программные сущности должны быть открыты для расширения, но закрыты для модификации."
Это значит, что код должен позволять добавлять новый функционал без изменения существующего кода.

🚩Почему это важно?

Меньше багов – изменения не ломают старый код.
Лучшая поддержка – новый функционал добавляется без переписывания старого.
Гибкость – можно расширять систему без изменения её базовой логики.

🚩Пример нарушения принципа OCP

Допустим, у нас есть класс, который рисует фигуры:
class ShapeDrawer {
func draw(shape: String) {
if shape == "circle" {
print("Рисуем круг")
} else if shape == "square" {
print("Рисуем квадрат")
}
}
}


🚩Как исправить? Используем OCP!

Лучше использовать наследование или протоколы, чтобы расширять функциональность, не меняя существующий код:
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