Swift | Вопросы собесов
2.15K subscribers
29 photos
960 links
Download Telegram
🤔 Что такое race condition?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
🎉 easyoffer 2.0 — релиз уже в этом месяце!

Вас ждут новые фичи, о которых мы ранее даже не упоминали. Они сделают путь к офферам ещё быстрее и эффективнее. Расскажу о них чуть позже 👀

В честь запуска мы готовим ограниченную акцию:

Первые 500 покупателей получат:
🚀 PRO тариф на 1 год с 50% скидкой

Что нужно сделать:

🔔 Подпишитесь на этот Telegram-канал, чтобы первыми узнать о старте релиза. Сообщение появится в нем раньше, чем где-либо еще — вы успеете попасть в число первых 500 и получить максимальную выгоду. 🎁 А еще только для подписчиков канала ценный бонус в подарок к PRO тарифу.

📅 Официальный запуск — уже совсем скоро.
Следите за новостями и не пропустите старт!
🤔 Чем отличается garbage collector и подсчет ссылок?

Garbage Collector (GC) и Automatic Reference Counting (ARC) – это два разных подхода к управлению памятью в программировании. Они решают одну задачу: автоматическое освобождение неиспользуемой памяти, но делают это по-разному.

🚩Garbage Collector (GC)

Java, Kotlin, C#, Python, JavaScript
- GC периодически просматривает всю память приложения и ищет объекты, на которые больше нет ссылок.
- Когда такие объекты находятся, они удаляются, а память освобождается.
- Это автоматический процесс, который запускается по мере необходимости.

🚩Подсчет ссылок (ARC - Automatic Reference Counting)

Где используется: Swift, Objective-C
- Каждый объект имеет счетчик ссылок (reference count).
- Когда переменная создает ссылку на объект, счетчик увеличивается.
- Когда переменная перестает ссылаться на объект, счетчик уменьшается.
- Когда счетчик достигает нуля, объект удаляется из памяти сразу же.
class Person {
var pet: Pet?
}

class Pet {
var owner: Person?
}

let person = Person()
let pet = Pet()

person.pet = pet
pet.owner = person // Теперь оба объекта держат друг друга, и ARC их не удалит


Решение – использовать weak:
class Pet {
weak var owner: Person? // Теперь утечки памяти не будет
}


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

– Value types — struct, enum, tuple.
– Reference types — class, function, NSObject-производные.


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

Если все переменные в коде сделать weak, объекты могут мгновенно удаляться из памяти, потому что никто не будет владеть ими (strong reference).

🚩Как работает `weak`?

- 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 уничтожен


🚩Когда `weak` полезен?

🟠Избегание циклов ссылок (retain cycle)
Например, между 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
🤔 В чём разница между fileprivate, private и public private(set) уровнями доступа?

- private — ограничивает доступ к свойству или методу в пределах текущей области, например, внутри одного класса или расширения.
- fileprivate — расширяет доступ до всего файла, в котором объявлен элемент. Позволяет разным типам в одном файле работать с приватными членами друг друга.
- public private(set) — свойство можно читать откуда угодно, но изменять только внутри текущего модуля. Это позволяет внешнему коду обращаться к значению, но не менять его напрямую.


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

Перед вызовом layoutIfNeeded() или layoutSubviews() в iOS-приложении, нужно изменить значение констрейнта и вызвать анимацию, если необходимо. Вот основные шаги:

🟠Обновление значения констрейнта
Перед вызовом layoutIfNeeded(), измените свойство констрейнта (например, constant у NSLayoutConstraint).
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
@IBOutlet weak var heightConstraint: NSLayoutConstraint!

override func viewDidLoad() {
super.viewDidLoad()

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.changeButtonHeight()
}
}

func changeButtonHeight() {
heightConstraint.constant = 100 // Меняем значение констрейнта
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded() // Перестраиваем макет
}
}
}


🟠Если меняется набор констрейнтов
Если нужно удалить/добавить констрейнты, используйте `activate()` / `deactivate()`.
var expanded = false

@IBOutlet weak var smallHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var largeHeightConstraint: NSLayoutConstraint!

func toggleHeight() {
expanded.toggle()

if expanded {
NSLayoutConstraint.deactivate([smallHeightConstraint])
NSLayoutConstraint.activate([largeHeightConstraint])
} else {
NSLayoutConstraint.deactivate([largeHeightConstraint])
NSLayoutConstraint.activate([smallHeightConstraint])
}

UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}


🟠Если работа идёт в `viewDidLoad()`
Во viewDidLoad() элементы ещё не отрисованы, поэтому layoutIfNeeded() не сработает. Используйте viewDidAppear() или вызовите layoutIfNeeded() после view.layoutIfNeeded().
override func viewDidLoad() {
super.viewDidLoad()
heightConstraint.constant = 100
view.layoutIfNeeded() // НЕ обновит макет, потому что он ещё не загружен
}


Решение
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

heightConstraint.constant = 100
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}


Разница между layoutIfNeeded() и setNeedsLayout()
heightConstraint.constant = 100
view.setNeedsLayout() // Обновление произойдет на следующем цикле рендера


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

Ключевое слово inout указывает, что переменная будет передана в функцию по ссылке, а не по значению. Это значит, что функция сможет изменить значение переменной за пределами своей области видимости. Чтобы передать значение в inout-параметр, перед именем переменной ставится &.


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

В Swift есть несколько инструментов для работы с многопоточностью и параллельным выполнением кода. Вот основные из них:

🟠GCD (Grand Central Dispatch) – главный инструмент для потоков
GCD – это низкоуровневая технология, позволяющая управлять задачами (тасками) в очередях (DispatchQueue).
DispatchQueue.global(qos: .background).async {
print("Фоновый поток")

DispatchQueue.main.async {
print("Вернулись в главный поток")
}
}


🟠OperationQueue – более удобный API для задач
OperationQueue – это более гибкая и объектно-ориентированная альтернатива GCD.
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2 // Ограничение на 2 задачи одновременно

queue.addOperation {
print("Операция 1")
}

queue.addOperation {
print("Операция 2")
}


🟠Actors – безопасная работа с потоками в Swift 5.5+
С actor можно работать с потоками без гонок данных, потому что все его свойства защищены от одновременного доступа.
actor Counter {
private var value = 0

func increment() {
value += 1
}

func getValue() -> Int {
return value
}
}

let counter = Counter()

Task {
await counter.increment()
print(await counter.getValue()) // Потокобезопасный доступ
}


🟠Task & Async/Await (Swift 5.5+) – современный подход к асинхронности
С async/await код становится читаемым и удобным.
func fetchData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 секунда задержки
return "Данные загружены"
}

Task {
let result = await fetchData()
print(result)
}


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

Расширение ячейки (UITableViewCell, UICollectionViewCell) делается через добавление вью, анимаций, динамических constraints или swipe-действий. Также можно использовать кастомные layout'ы или auto-sizing.


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

Половина массива — это подмножество элементов массива, которое составляет примерно 50% его длины. В зависимости от контекста, это может быть:
Первая половина – элементы от начала массива до середины.
Вторая половина – элементы от середины до конца массива.
Любая подгруппа, близкая к 50% – например, при нечетном количестве элементов можно взять либо на один элемент больше, либо меньше.

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let middleIndex = array.count / 2 // Делим пополам

let firstHalf = Array(array[..<middleIndex]) // Первая половина
let secondHalf = Array(array[middleIndex...]) // Вторая половина

print(firstHalf) // [1, 2, 3, 4, 5]
print(secondHalf) // [6, 7, 8, 9, 10]


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

Разбиение данных для обработки (например, сортировка "разделяй и властвуй").Разделение элементов для параллельной обработки.
Разбиение коллекций при пагинации.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6
🤔 Почему порядок ключей будет сохраняться между мутациями в словаре?

Начиная с Swift 4, стандартный Dictionary сохраняет порядок вставки ключей. Даже при изменении значений или добавлении новых элементов порядок сохраняется, пока явным образом не удаляются ключи или не происходит массовая перераспределённая перестройка.
Это стало возможным благодаря обновлённой реализации хеш-таблицы внутри Dictionary.


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

UIView всегда имеет CALayer, так как UIView — это обёртка над CALayer в UIKit.
CALayer может существовать без UIView, потому что это низкоуровневый элемент Core Animation, который не зависит от UIKit.

🚩`UIView` всегда содержит `CALayer`

Каждый UIView внутри себя содержит CALayer, который отвечает за отрисовку.
let view = UIView()
print(view.layer) // Всегда существует!


🚩`CALayer` может существовать без `UIView`

CALayer можно создать и добавить в иерархию без UIView.
let layer = CALayer()
layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor

if let window = UIApplication.shared.windows.first {
window.layer.addSublayer(layer) // Добавляем без UIView!
}


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

Проблема возникает, когда задача с более низким приоритетом получает доступ к ресурсу раньше задачи с высоким приоритетом. Это может происходить из-за отсутствия синхронизации или блокировок — пример: priority inversion.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое мьютекс (mutex)?

Мьютекс (от англ. "mutex" - mutual exclusion, взаимное исключение) — это механизм синхронизации, используемый в многопоточном программировании для предотвращения одновременного доступа нескольких потоков к общим ресурсам, таким как переменные, структуры данных или файлы. Он помогает избежать состояния гонки (race condition), когда результат выполнения программы зависит от неопределённого порядка доступа потоков к ресурсу.

🚩Основные концепции мьютекса

🟠Взаимное исключение
Мьютекс обеспечивает доступ к общему ресурсу только одному потоку в каждый момент времени. Когда один поток захватывает мьютекс, другие потоки должны ждать, пока мьютекс не будет освобождён.

🟠Захват и освобождение
Поток захватывает мьютекс перед доступом к общему ресурсу и освобождает его после завершения работы с этим ресурсом. Если мьютекс уже захвачен другим потоком, текущий поток будет блокирован до тех пор, пока мьютекс не будет освобождён.

🚩Пример использования мьютекса в Swift

import Foundation

class SafeCounter {
private var value = 0
private let lock = NSLock()

func increment() {
lock.lock() // Захват мьютекса
value += 1
lock.unlock() // Освобождение мьютекса
}

func getValue() -> Int {
lock.lock() // Захват мьютекса
let currentValue = value
lock.unlock() // Освобождение мьютекса
return currentValue
}
}

let counter = SafeCounter()
DispatchQueue.global().async {
for _ in 0..<1000 {
counter.increment()
}
}

DispatchQueue.global().async {
for _ in 0..<1000 {
counter.increment()
}
}

// Подождём немного, чтобы дать потокам закончить работу
Thread.sleep(forTimeInterval: 1)
print("Final counter value: \(counter.getValue())")


🚩Плюсы и минусы

Безопасность данных
Мьютексы защищают общие ресурсы от одновременного доступа, предотвращая повреждение данных.

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

Мёртвые блокировки (Deadlocks)
Если мьютексы захватываются в неправильном порядке, это может привести к ситуации, когда два или более потока блокируют друг друга, ожидая освобождения мьютексов.

Производительность
Чрезмерное использование мьютексов может привести к снижению производительности из-за увеличения времени ожидания потоков.

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

Обычно используются:
- pushViewController (в UINavigationController);
- present(_:animated:) — для модального показа;
- В SwiftUI — NavigationStack, .sheet, .fullScreenCover.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Расскажи про механизм отмены в 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
🤔 Какие есть в enum кейсы?

Enum может содержать:
- Plain cases: case success, failure
- Associated values: case data(String)
- Raw values: case error = 404
- Также поддерживаются indirect и вложенные enum.


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

Классы — это ссылочные типы в 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
🤔 Что происходит в системе, когда мы тапаем по экрану?

Когда пользователь касается экрана, происходит следующий процесс:
1. Аппаратный слой (дисплей) фиксирует касание и передаёт его в iOS.
2. Система генерирует объект события (UIEvent, UITouch).
3. Событие передаётся в главное окно (UIWindow) и далее — вью-контроллерам и иерархии UIView.
4. Система запускает hit-testing — определяет, какая вьюшка находится под точкой касания.
5. Вызываются методы:
- hitTest(_:with:) — определяет целевую вью.
- touchesBegan(_:with:), touchesMoved, touchesEnded — передают событие в конкретную вью.


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