Swift | Вопросы собесов
2.14K subscribers
28 photos
957 links
Download 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
🔥4
🤔 За что отвечают Content Hugging Priority?

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


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

Подписку на уведомления (NotificationCenter), KVO или Combine в жизненном цикле UIViewController лучше размещать в методах, где гарантируется её актуальность и корректное удаление.

🟠Подписка в `viewDidLoad()`
Подписка на события обычно происходит в `viewDidLoad()`, так как этот метод вызывается один раз при создании контроллера.
override func viewDidLoad() {
super.viewDidLoad()

NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification),
name: .someNotification,
object: nil
)
}

@objc func handleNotification(_ notification: Notification) {
print("Получено уведомление")
}


🟠Подписка в `viewWillAppear()` – если уведомления нужны только при отображении экрана
Если подписка должна работать только когда экран на экране, используем viewWillAppear().
var cancellable: AnyCancellable?

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

cancellable = NotificationCenter.default.publisher(for: .someNotification)
.sink { _ in
print("Событие получено")
}
}


🟠`viewWillDisappear()` – отписка от событий
Когда контроллер скрывается, подписки можно удалить, чтобы избежать ненужных вызовов.
Удаление подписки на NotificationCenter:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

NotificationCenter.default.removeObserver(self, name: .someNotification, object: nil)
}


Удаление Combine подписки (cancellable)
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

cancellable?.cancel()
cancellable = nil
}


🟠`deinit` – отписка, если подписка создаётся в `viewDidLoad()`
Если подписка работает на протяжении всего жизненного цикла контроллера, её можно удалить в `deinit`.
deinit {
NotificationCenter.default.removeObserver(self)
}


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

init — это конструктор, который отвечает за инициализацию объекта: присваивает значения свойствам, вызывает базовый инициализатор, устанавливает зависимости. Вызывается при создании экземпляра класса или структуры.


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

Stack (стек) – это структура данных, работающая по принципу LIFO (Last In, First Out – "последним пришел, первым ушел").

🚩Пример реализации стека в Swift

В Swift нет встроенного стека (кроме Array), но можно создать свой:
struct Stack<T> {
private var elements: [T] = []

mutating func push(_ item: T) {
elements.append(item)
}

mutating func pop() -> T? {
return elements.popLast() // Удаляет и возвращает верхний элемент
}

func peek() -> T? {
return elements.last // Возвращает верхний элемент без удаления
}

func isEmpty() -> Bool {
return elements.isEmpty
}
}

// Пример использования:
var stack = Stack<Int>()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.pop()!) // 30
print(stack.peek()!) // 20
print(stack.isEmpty()) // false


🚩Где используется стек?

Обратный порядок выполнения (рекурсия) – стек вызовов функций.
Алгоритмы (обратная польская нотация, DFS – поиск в глубину)
История действий (назад-вперед в браузере, отмена в редакторе).

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

На iOS используют App Groups — механизм общего контейнера, доступного сразу для нескольких приложений одного разработчика. Также можно использовать Keychain Sharing или URL Scheme, если не требуется постоянный доступ к данным.


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

Объектно-ориентированное программирование (ООП) — это парадигма, основанная на концепции "объектов", которые могут содержать данные в виде полей (часто называемых атрибутами или свойствами) и код в виде процедур (часто называемых методами). ООП фокусируется на использовании объектов для моделирования реального мира (или абстракций), облегчая разработку и поддержку сложных программ. Существует четыре основных принципа:

🟠Инкапсуляция
Механизм ООП, который объединяет данные (атрибуты) и код (методы), манипулирующий этими данными, внутри одного объекта и скрывает детали реализации от внешнего использования. Это позволяет защитить внутреннее состояние объекта от прямого доступа извне и обеспечить контролируемый интерфейс для работы с этим объектом.

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

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

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

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

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


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

– UIView,
– UIViewController,
– UIWindow,
– UIApplication.
Они могут обрабатывать события и передавать их по цепочке.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🤔 Есть функции с не вложенными двумя циклами — в чём сложность её выполнения?

Даже при отсутствии вложенности, сложность может быть O(n^2), если один цикл зависит от результата работы предыдущего. Также важно, как обрабатываются данные внутри: сложные операции в теле могут значительно повлиять на производительность.


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

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

🟠Статическая связка Swift Runtime
Swift — это относительно новый язык, и его стандартная библиотека не встроена в iOS (как, например, Objective-C runtime). Это значит, что при компиляции приложения в его бинарь включаются стандартные Swift-библиотеки.

🟠Bitcode и архитектуры (Fat Binary)
При публикации в App Store, Xcode компилирует приложение для нескольких архитектур (arm64, armv7, x86_64). Это называется Fat Binary — один исполняемый файл включает версии для разных процессоров.

🟠Swift ABI Stability – улучшение, но не панацея
С версии Swift 5.0 ABI (Application Binary Interface) стабилизирован. Это означает, что в iOS 12.2+ уже есть встроенные Swift-библиотеки.

🟠Использование SwiftUI и Combine
SwiftUI и Combine — новые технологии, они не так оптимизированы, как UIKit. При их использовании код разрастается за счёт декларативного подхода и дополнительной логики от Apple.

🟠Дополнительные ресурсы и Assets
Если приложение использует локализацию, изображения, шрифты, CoreML, ARKit, это тоже увеличивает размер .ipa.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Что такое поток безопасности (thread-safety)?

Потокобезопасность — это свойство кода/объекта, означающее, что он может использоваться из разных потоков одновременно без ошибок и гонок данных.
Потокобезопасный код:
- Не вызывает крашей.
- Не вызывает конфликтов доступа.
- Защищает внутреннее состояние при параллельном использовании.
В Swift thread-safety достигается через:
- Синхронизацию (DispatchQueue, lock).
- Immutable-структуры.
- Использование actor и
@MainActor.

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

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

🚩Основные понятия

🟠Поток (Thread)
Минимальная единица обработки, которая может быть выполнена операционной системой.

🟠Конкуренция (Concurrency)
Способность программы делать прогресс в нескольких задачах одновременно. Конкуренция достигается за счёт переключения между задачами.

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Если экран обладает и альбомной, и портретной ориентацией, что удобнее использовать: AutoLayout или Frame?

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


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

Если вы создадите свою структуру (struct) в Swift, то сама по себе она не будет автоматически защищена авторским правом (copyright). Авторские права относятся к защите исходного кода как текста, но не к самим структурам данных или идеям.

🚩Как защитить свою структуру?

🟠Авторские права (Copyright)
автоматически защищает исходный код.
Можно указать копирайт в файле:
// Copyright © 2025 [Ваше имя]. All rights reserved.


🟠Лицензия (MIT, Apache, GPL и т. д.)
если публикуете код в открытом доступе.
Позволяет контролировать, как другие могут использовать ваш код.
The MIT License (MIT)
Copyright (c) 2025 [Ваше имя]
Permission is hereby granted, free of charge, to any person obtaining a copy...


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

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

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


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

Утечка памяти (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` ссылки
Слабые (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`, если объект всегда будет существовать
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 удалён"


🟠Разрывать циклы в замыканиях (`[weak self]`)
Замыкания захватывают объекты, создавая циклические ссылки.
Проблема: self удерживается замыканием
class ViewController {
var closure: (() -> Void)?

func setup() {
closure = {
print(self) // Удерживает self, создавая цикл!
}
}

deinit { print("ViewController удалён") }
}

var vc: ViewController? = ViewController()
vc?.setup()
vc = nil // "ViewController" НЕ удалится


🚩Как найти утечки памяти?

🟠Использовать `Instrument – Leaks` в Xcode
- Открываем Xcode > Product > Profile.
- Выбираем Leaks.
- Запускаем приложение и проверяем, остаются ли объекты в памяти.

🟠Проверить `deinit`
Если метод deinit не вызывается – значит, объект утёк в память.
class Test {
deinit { print("Test удалён") }
}

var obj: Test? = Test()
obj = nil // Должно напечатать "Test удалён"


🟠Включить `Malloc Stack Logging`
- В Xcode открываем "Debug Memory Graph" (нажимая значок в Debugger).
- Смотрим, какие объекты остались в памяти.

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

В Swift компилятор использует статическую диспетчеризацию (на этапе компиляции), если это final, struct, enum, или static. В остальных случаях — динамическую диспетчеризацию через таблицу методов (vtable) для классов. Метод выбирается по сигнатуре, контексту и типу.


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