Swift | Вопросы собесов
2.22K subscribers
30 photos
962 links
Download Telegram
🤔 Что такое поведенческий паттерн?

Это паттерн, описывающий взаимодействие между объектами, как они передают управление и данные. Поведенческие паттерны помогают организовать структуру общения и избегать жёсткой связанности. Примеры: Observer, Strategy, Command, State, Mediator.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
Ура, друзья! Изиоффер переходит в публичное бета-тестирование!

🎉 Что нового:
🟢Анализ IT собеседований на основе 4500+ реальных интервью
🟢Вопросы из собеседований с вероятностью встречи
🟢Видео-примеры ответов на вопросы от Senior, Middle, Junior грейдов
🟢Пример лучшего ответа
🟢Задачи из собеседований
🟢Тестовые задания
🟢Примеры собеседований
🟢Фильтрация всего контента по грейдам, компаниям
🟢Тренажер подготовки к собеседованию на основе интервальных повторений и флеш карточек
🟡Тренажер "Реальное собеседование" с сценарием вопросов из реальных собеседований (скоро)
🟢Автоотклики на HeadHunter
🟢Закрытое сообщество easyoffer


💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (15000₽ → 7500₽)

🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое Satisfiable?

В контексте Swift термин Satisfiable (удовлетворяемый) относится к тому, может ли конкретный тип соответствовать (удовлетворять) требованиям протокола.

🚩Что значит, что протокол satisfiable?
Протокол считается satisfiable, если его можно реализовать без противоречий. Например, если в протоколе указаны требования, которые могут быть выполнены в классе или структуре.
protocol Animal {
var name: String { get }
func speak()
}

struct Dog: Animal {
var name = "Барсик"

func speak() {
print("Гав-гав")
}
}

let dog = Dog()
dog.speak() // "Гав-гав"


🚩Когда протокол не satisfiable?

Протокол не может быть удовлетворён (то есть, не satisfiable), если он содержит требования, которые невозможно реализовать в конкретном типе.
protocol Impossible {
var value: Self { get } // Self требует, чтобы свойство содержало сам тип
}

struct Example: Impossible {
var value: Example // ОШИБКА: бесконечная рекурсия!
}


🚩Проверка satisfiability в Swift

Если вы видите ошибку Protocol 'X' cannot be satisfied, значит, Swift не может найти способ правильно реализовать все его требования.
Проверьте ассоциированные типы и Self – они должны корректно ссылаться на реализуемый тип.
Проверьте требования протокола – убедитесь, что все свойства и методы могут быть реализованы в классе/структуре.
Попробуйте использовать any Protocol – если Self создаёт проблемы, возможно, нужно использовать any:
   func test(value: any Impossible) { } // Позволяет работать с протоколом без строгого Self


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

Task — это единица асинхронной работы, которая может быть запущена, приостановлена, возобновлена и завершена. В Swift и других языках (например, C#, Kotlin) Task представляет собой объект, выполняющий асинхронный код, часто с возможностью получения результата. Задачи помогают структурировать конкурентный код более удобно, чем вручную через потоки.


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

Если вы хотите задать отступы (margins, padding) для UIView в жизненном цикле UIViewController, то важно выбрать правильный момент, когда размеры view уже определены.

🚩Пример установки отступов в `viewDidLayoutSubviews()`

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
🤔 Как сохранять и читать структуру из UserDefaults?

Структура должна реализовать Codable, сериализуется в Data через JSONEncoder, сохраняется в UserDefaults. При чтении — извлекается и декодируется JSONDecoder.


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

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

🚩Что такое Future?

Future (или Promise в некоторых реализациях) — это объект, который представляет значение, которое станет доступным в будущем после завершения асинхронной операции. Это удобно, когда нужно работать с кодом, который выполняется не мгновенно
Запросы в сеть (API)
Чтение файлов
Долгие вычисления
В Swift Future чаще всего используется в рамках Combine.

🚩Как работает Future в Swift (на примере Combine)?

В Combine есть структура Future, которая позволяет создать асинхронную операцию и подписаться на ее результат:
import Combine

// Функция, которая возвращает Future
func fetchData() -> Future<String, Error> {
return Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
let success = Bool.random() // Симулируем успех или ошибку

if success {
promise(.success("Данные загружены!"))
} else {
promise(.failure(NSError(domain: "Ошибка загрузки", code: -1, userInfo: nil)))
}
}
}
}

// Используем Future
let future = fetchData()

let cancellable = future.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Завершено без ошибок")
case .failure(let error):
print("Ошибка: \(error.localizedDescription)")
}
}, receiveValue: { value in
print("Получены данные: \(value)")
})


🚩Когда использовать Future?

Когда нужна одноразовая асинхронная операция (например, запрос в сеть)
Когда используешь Combine и хочешь обернуть асинхронный код в реактивный стиль
Если в будущем планируешь объединять несколько асинхронных операций (композиция Future)

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

Жизненный цикл UIViewController запускается:
- При инициализации и отображении контроллера (вручную или через навигацию).
- Основные методы:
- viewDidLoad()
- viewWillAppear()
- viewDidAppear()
- viewWillDisappear()
- viewDidDisappear()
Чтобы вызвать жизненный цикл вручную:
- Представить контроллер:
- Или встроить в навигацию:


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

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

🚩Объект-зависимый и объект-зависимость

Когда один объект (например, 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, VIPER, DI)

В MVVM зависимость между ViewController и ViewModel.
В VIPER модули зависят друг от друга, но слабо связаны через протоколы.
В DI (Dependency Injection) зависимости передаются снаружи, что повышает тестируемость и гибкость.

🚩Менеджеры зависимостей

Чтобы управлять внешними зависимостями (библиотеками), используются
Swift Package Manager (SPM)
CocoaPods
Carthage

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

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


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

В Swift нет множественного наследования классов, но можно использовать множественное наследование через протоколы.

🚩Почему нет множественного наследования классов?

Swift запрещает множественное наследование классов, потому что оно может привести к конфликтам и алмазной проблеме (diamond problem).
Допустим, в языке с поддержкой множественного наследования у нас есть два родительских класса с одинаковым методом:
class A {
public:
void greet() { cout << "Hello from A"; }
};

class B {
public:
void greet() { cout << "Hello from B"; }
};

// C наследуется от A и B
class C : public A, public B {};

C obj;
obj.greet(); // Какой метод вызвать? A или B?


🚩Как обойти ограничение? Используем протоколы!

В Swift можно реализовать множественное наследование через протоколы, поскольку класс может соответствовать нескольким протоколам одновременно.
protocol Flyable {
func fly()
}

protocol Swimmable {
func swim()
}

class Animal {}

class Duck: Animal, Flyable, Swimmable {
func fly() {
print("Утка летит")
}

func swim() {
print("Утка плывёт")
}
}

let duck = Duck()
duck.fly() // Утка летит
duck.swim() // Утка плывёт


🚩Что делать, если нужен код по умолчанию?

Если хочется, чтобы протокол предоставлял реализацию по умолчанию (почти как родительский класс), можно использовать extension:
protocol Walker {
func walk()
}

extension Walker {
func walk() {
print("Иду вперёд")
}
}

class Person: Walker {}

let human = Person()
human.walk() // "Иду вперёд" (метод взят из extension)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что известно про UICollectionViewCompositionalLayout (composition layout)?

Это мощный способ построения гибких layout'ов без сложного наследования от UICollectionViewLayout. Используется иерархия: Item → Group → Section → Layout. Позволяет создать сложные, адаптивные, горизонтальные/вертикальные списки, карусели и пр.


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

В программировании стек (stack) — это структура данных и область памяти, используемая для хранения временных данных. В зависимости от контекста, стек может существовать в нескольких местах.

🟠Стек вызовов (Call Stack)
Это главная область памяти в оперативной памяти (RAM), где хранятся:
- Локальные переменные функций.
- Адреса возврата после завершения функции.
- Контекст выполнения программы.
func functionA() {
functionB()
}

func functionB() {
print("Вызов B")
}

functionA()

func infiniteRecursion() {
infiniteRecursion() // Бесконечный вызов
}


🟠Стек в структуре данных (например, `Array`)
В Swift можно реализовать стек вручную, используя массив (Array).
struct Stack<T> {
private var elements: [T] = []

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

mutating func pop() -> T? {
return elements.popLast()
}
}

var stack = Stack<Int>()
stack.push(10)
stack.push(20)
print(stack.pop()!) // 20


🟠Потоковый стек (Thread Stack)
Каждый поток (Thread) в многопоточном программировании получает свой стек.
DispatchQueue.global().async {
print("Фоновый поток")
}
print("Главный поток")


🟠Стек в автоматическом управлении памятью (ARC)
Swift использует Automatic Reference Counting (ARC) для управления памятью.
Когда объект больше не нужен, он удаляется из памяти (в том числе из стека).
func createPerson() {
let person = "Иван" // Создаётся в стеке
print(person)
}

createPerson() // Переменная person удаляется при выходе из функции


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2
🤔 За что отвечает "L" в "SOLID"?

"L" в SOLID — это принцип Лисков (Liskov Substitution Principle), который гласит, что объект дочернего класса должен корректно работать там, где используется объект родительского класса. Это помогает создавать устойчивые и легко расширяемые архитектуры.

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

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

🤔 Основные типы данных

🟠Примитивные типы данных
Представляют целые числа. Int, UIn
       let age: Int = 25


Представляют дробные числа. Float, Double
       let pi: Double = 3.14159


Представляют логические значения true или false. Bool
       let isActive: Bool = true


Представляют отдельные символы. Character
       let letter: Character = "A"


🟠Составные типы данных (Composite data types)
Представляют последовательности символов. String
       let greeting: String = "Hello, World!"


Представляют упорядоченные коллекции элементов одного типа. Array<T>
       let numbers: [Int] = [1, 2, 3, 4, 5]


Представляют коллекции пар ключ-значение. Dictionary<Key, Value>
       let user: [String: String] = ["name": "Alice", "age": "30"]


Представляют коллекции уникальных элементов. Set<T>
       let uniqueNumbers: Set<Int> = [1, 2, 3, 4, 5]


🟠Пользовательские типы данных (User-defined data types)
Представляют тип данных с набором связанных значений. enum
       enum CompassPoint {
case north
case south
case east
case west
}


Представляют группы связанных значений. struct
       struct Person {
var name: String
var age: Int
}
let person = Person(name: "Alice", age: 30)


Представляют объекты с состоянием и поведением. class
       class Car {
var model: String
var year: Int

init(model: String, year: Int) {
self.model = model
self.year = year
}
}
let car = Car(model: "Tesla", year: 2021)


🟠Специальные типы данных
Представляют группы нескольких значений различных типов. (Type1, Type2, ...)
       let coordinates: (Int, Int) = (10, 20)


Представляют значение, которое может быть либо некоторым значением, либо nil. Optional<T>
       var optionalName: String? = "Alice"


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

1. Это механизм синхронизации, который ограничивает доступ к ресурсу только одному потоку в определённый момент времени.
2. Он блокирует другие потоки до завершения работы текущего.
3. Используется для предотвращения race condition при работе с общими данными.


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

Это высокоуровневый механизм синхронизации, который объединяет взаимное исключение (mutex) и условные переменные (condition variables) для управления доступом к объектам в многопоточной среде.

🚩Как работает

🟠Взаимное исключение (Mutual Exclusion)
Только один поток может выполнить защищенный блок кода в любой момент времени.
🟠Условные переменные (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
}
}
}


С NSLock
class 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_exit
class 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
🤔 Как управлять зависимостями?

Через менеджеры зависимостей:
- CocoaPods, Carthage, Swift Package Manager — позволяют подключать внешние библиотеки, управлять их версиями, следить за обновлениями. Также возможна ручная интеграция, но она менее гибкая и масштабируемая.


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

Барьер (Barrier) – это механизм синхронизации потоков, который позволяет контролировать порядок выполнения операций** в многопоточной среде.

🚩Барьеры памяти (Memory Barriers)

Используются в многопоточном программировании для управления порядком операций с памятью.
В многопоточной среде процессоры и компиляторы могут оптимизировать порядок команд, что может привести к непредсказуемому поведению. Барьеры памяти предотвращают это.
#include <stdatomic.h>

atomic_int sharedValue = 0;

void updateValue() {
atomic_store_explicit(&sharedValue, 10, memory_order_release);
}

void readValue() {
int value = atomic_load_explicit(&sharedValue, memory_order_acquire);
}


🚩Барьеры в GCD (`dispatch_barrier`)

Используются в Grand Central Dispatch (GCD)** для контроля порядка выполнения задач в DispatchQueue.
- Позволяет блокировать очередь на время выполнения задачи.
- Все задачи до барьера выполняются параллельно.
- Барьер ждёт завершения всех предыдущих задач, выполняется эксклюзивно, затем разрешает следующие задачи.
let queue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)

queue.async {
print("Задача 1")
}
queue.async {
print("Задача 2")
}

// БАРЬЕРНАЯ ОПЕРАЦИЯ
queue.async(flags: .barrier) {
print("🔴 Барьер: все предыдущие задачи завершены, выполняюсь один!")
}

queue.async {
print("Задача 3")
}


🚩Барьеры в OpenMP (Параллельные вычисления)

В OpenMP (#pragma omp barrier) ждёт завершения всех потоков перед выполнением следующего кода.
#pragma omp parallel
{
printf("До барьера\n");
#pragma omp barrier
printf("После барьера\n");
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Какие ещё бывают type?

– Int, Double, String, Bool — базовые типы,
– struct, class, enum, tuple,
– Optional,
– Protocol,
– Function,
– Any, AnyObject, Never.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🔥2