Swift | Вопросы собесов
2.13K subscribers
28 photos
946 links
Download Telegram
🤔 Что происходит с параллельной очередью при запуске barrier-операции?

Операция с barrier блокирует доступ к параллельной очереди — она запускается только после завершения всех текущих задач и до начала новых. Это нужно для потокобезопасной записи.

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

Да, если хочешь сохранить или передать её как Codable, Hashable, Equatable и т.д. Протоколы обеспечивают интерфейс и поддержку функционала на уровне абстракции.


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

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

🤔Зачем нужен @autoclosure?

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

🚩Пример без

Допустим, у нас есть функция, которая принимает замыкание
func logMessage(_ message: () -> String) {
print("Лог: \(message())")
}

// Вызываем функцию, передавая замыкание
logMessage { "Сообщение: \(2 + 2)" }

🚩Пример с

Теперь используем `@autoc чтобы сделать вызов функции проще
func logMessage(_ message: @autoclosure () -> String) {
print("Лог: \(message())")
}

// Теперь аргумент можно передавать без {}
logMessage("Сообщение: \(2 + 2)")

🚩Где это полезно?

🟠`assert` и precondition
Стандартные функции Swift используют @autoclosure, чтобы избежать вычисления аргументов, если проверка не нужна:
assert(2 + 2 == 4, "Ошибка: 2 + 2 не равно 4!")

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

🤔Зачем нужен `@autoclosure`?

Обычно его используют для улучшения читаемости кода, особенно когда нужно.`@autoc но если нужно сохранить замыкание для будущего выполнения, это можно сделать рый автоматически превращает переданное выражение в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится.

🤔Зачем нужен `@autoclosure`?

Обычно его используют для улучшения читаемости кода, особенно когда нужно лениво вычислять аргумент функции.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3
🤔 Преимущества и недостатки синхронного и асинхронного соединения?

Синхронное соединение:
Преимущества:
- Простота реализации
- Последовательность выполнения
Недостатки:
- Блокирует поток
- Неэффективно при работе с сетью или ожиданием
Асинхронное соединение:
Преимущества:
- Не блокирует основной поток
- Позволяет обрабатывать несколько задач одновременно
Недостатки:
- Более сложная логика
- Труднее отлаживать и тестировать


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

Свойства "Content Hugging Priority" и "Content Compression Resistance Priority" играют ключевую роль в системе Auto Layout. Эти свойства помогают определить, как вьюшки (views) должны быть отформатированы и как они реагируют на изменения в доступном пространстве в интерфейсе пользователя. Рассмотрим подробнее, что означает каждое из этих свойств и как они используются в разработке интерфейсов.

🚩Content Hugging Priority

Определяет, насколько сильно вьюшка должна "обнимать" своё содержимое. Это свойство указывает на желательность вьюшки быть как можно ближе к своим внутренним размерам, основанным на своем содержимом.

🚩Content Compression Resistance Priority

Определяет, насколько сильно вьюшка должна противостоять сжатию размеров меньше, чем размеры её содержимого.

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

@State — локальное состояние внутри view, простое и недоступное извне.
@StateObject — объект со сложным состоянием, живёт в view.
@ObservedObject — подписка на внешний объект, но управляется извне.

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

В iOS существует несколько ленивых (lazy) контейнеров и вью, которые откладывают создание или загрузку элементов до момента их фактического использования.

🚩`lazy var` (ленивые свойства)
Обычное свойство инициализируется сразу, а lazy – только при первом вызове.
class Example {
lazy var expensiveObject: Data = {
print("Объект создан!")
return Data()
}()
}

let obj = Example()
print("Объект ещё не создан")
_ = obj.expensiveObject // Только теперь создастся


🚩`LazySequence` и `LazyCollection`

Если вы хотите избежать лишних вычислений, можно использовать ленивую последовательность:
let numbers = (1...1000).lazy.map { $0 * 2 } // Не вычисляется сразу!
print(numbers.first!) // Только теперь вычисляется первый элемент


🚩`LazyVStack`, `LazyHStack`, `LazyGrid` (SwiftUI)

В отличие от обычных VStack и HStack, ленивые версии создают элементы только при прокрутке.
ScrollView {
LazyVStack {
ForEach(0..<1000) { index in
Text("Элемент \(index)")
}
}
}


🚩`UITableView` и `UICollectionView` (UIKit)

Они работают по принципу переиспользования ячеек, загружая их только когда нужно.
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
👍1
🤔 Чем отличается serial от компарат?

serial — вероятно, ошибка или сокращение. Возможно, имелся в виду SerialQueue (последовательная очередь).
Comparable — это протокол для сравнения объектов (<, >, ==), используется для сортировок и упорядочивания.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊13
🤔 Для каких сущностей работает copy on write?

Механизм Copy-on-Write (CoW) используется для оптимизации производительности и использования памяти при копировании объектов. Этот механизм особенно полезен для неизменяемых (immutable) структур данных. CoW часто ассоциируется со стандартными коллекциями и собственными типами данных, реализованными как структуры (value types), такие как Array, String, Dictionary, и Set.

🚩Принцип работы Copy-on-Write

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

🚩Как это работает в Swift

Автоматически применяет механизм CoW к своим стандартным коллекциям, таким как Array, String, Dictionary, и Set. Это означает, что при передаче этих объектов в функции или при их копировании реальное дублирование данных происходит только в случае модификации одной из копий. Таким образом, если вы создаёте копию массива и не изменяете его, обе переменные будут указывать на одни и те же данные в памяти. Как только вы модифицируете одну из копий, Swift создаст реальную копию данных для этой копии, обеспечивая независимость данных между оригиналом и копией.
var originalArray = [1, 2, 3]
var copiedArray = originalArray // На этом этапе данные не дублируются

copiedArray.append(4) // Теперь данные копируются, потому что copiedArray модифицируется


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

Это механизм динамического диспетчинга в Swift, используемый для работы с протоколами.
- Если структура или класс реализуют протокол, Swift создает Witness Table, хранящую указатели на методы.
- Это позволяет динамически вызывать методы, объявленные в протоколе, даже если тип не известен во время компиляции.


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

В 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
🤔 Какие различия между HEAD, GET, POST, PUT?

- HEAD — как GET, но без тела. Используется, чтобы узнать метаинформацию (например, размер файла или заголовки) без загрузки содержимого.
- GET — запрашивает данные с сервера. Не изменяет состояние сервера.
- POST — отправляет данные на сервер для создания нового ресурса. Неидемпотентен.
- PUT — отправляет данные для полного обновления существующего ресурса. Идемпотентен.


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

Структуры (struct) – это один из основных типов данных в Swift. Они значимые (value type), то есть при передаче копируются, а не передаются по ссылке.

🚩Главные особенности `struct`

Value type – при передаче копируется (в отличие от классов)
Нет ARC (автоматического подсчета ссылок) – производительность выше
Могут иметь методы, свойства, инициализаторы
Работают с протоколами (protocol-oriented programming)
Не поддерживают наследование

🚩Пример структуры

struct Car {
var model: String
var year: Int

func description() -> String {
return "\(model) – \(year)"
}
}

let car1 = Car(model: "Tesla", year: 2023)
var car2 = car1 // Создается копия

print(car1.description()) // Tesla – 2023
print(car2.description()) // Tesla – 2023

car2.year = 2024 // Изменяем car2, но car1 остается прежним
print(car1.year) // 2023
print(car2.year) // 2024


🚩Мутируемые структуры (`mutating`)

По умолчанию методы не могут изменять свойства структуры. Чтобы изменить их внутри метода, нужно использовать mutating
struct Counter {
var count = 0

mutating func increment() {
count += 1
}
}

var counter = Counter()
counter.increment()
print(counter.count) // 1


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 За что отвечают Compression Resistance Priority?

Отвечают за сопротивление сжатию UI-элемента в ограниченном пространстве. Элемент с более высоким приоритетом будет меньше сжиматься, чем элемент с более низким значением.


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

NSManagedObjectID – это уникальный идентификатор объекта в Core Data, который остаётся неизменным на протяжении всего жизненного цикла объекта.

🚩Как сохранить `NSManagedObjectID`?

Используем uriRepresentation() – это строка (URL), которая уникально идентифицирует объект.
func saveObjectID(_ object: NSManagedObject) {
let objectID = object.objectID.uriRepresentation().absoluteString
UserDefaults.standard.set(objectID, forKey: "savedObjectID")
}


🚩Как восстановить объект по `NSManagedObjectID`?

1. Получаем URL из UserDefaults.
2. Преобразуем URL в NSManagedObjectID.
3. Загружаем объект из Core Data.
func fetchSavedObjectID(context: NSManagedObjectContext) -> NSManagedObject? {
guard let objectIDString = UserDefaults.standard.string(forKey: "savedObjectID"),
let objectURL = URL(string: objectIDString) else { return nil }

let objectID = context.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: objectURL)

if let objectID = objectID {
return context.object(with: objectID)
}
return nil
}


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

UIView — это высокоуровневая оболочка, которая управляет взаимодействием, событиями, отрисовкой, а CALayer — низкоуровневая графическая часть. Через UIView проще управлять UI и логикой, layer — для кастомной графики и анимаций.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🤔 Что значит value type принадлежит reference type?

Это ситуация, когда value type (например, struct) находится внутри reference type (например, класса), и тогда доступ к нему уже регулируется по ссылке через обёртку.


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

В Swift ключи в словаре (Dictionary) должны быть уникальными и сравниваться между собой. Поэтому, если вы хотите использовать*свою структуру в качестве ключа, она должна соответствовать протоколу Hashable.

🚩Что нужно?

Структура должна соответствовать Hashable
Должен быть реализован hash(into:) или использовать Equatable + Hashable автоматически
Свойства структуры должны быть Hashable (если String, Int, Double – все ок)

🚩Пример кастомной структуры в `Dictionary`

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:)`

Если нужно кастомное хеширование, можно реализовать 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