Swift | Вопросы собесов
2.14K subscribers
28 photos
927 links
Download Telegram
🤔 Расскажи про кодирование и декодирование в user defaults

UserDefaults — это хранилище для сохранения простых данных (строки, числа, массивы). Но если нужно сохранить сложные объекты, их сначала кодируют в `Data` (Codable), а затем сохраняют.

🟠Сохранение и загрузка простых данных
Для примитивных типов (строки, числа, массивы, словари) UserDefaults работает без кодирования:
let defaults = UserDefaults.standard

// Сохранение
defaults.set("Иван", forKey: "username")
defaults.set(25, forKey: "age")

// Чтение
let name = defaults.string(forKey: "username") ?? "Нет имени"
let age = defaults.integer(forKey: "age")

print(name, age) // Иван 25


🟠Сохранение сложных объектов (Codable)
Если нужно сохранить свой объект, сначала его нужно закодировать в Data.
struct User: Codable {
let name: String
let age: Int
}


Сохранение в UserDefaults
let user = User(name: "Иван", age: 25)
let defaults = UserDefaults.standard

if let encoded = try? JSONEncoder().encode(user) {
defaults.set(encoded, forKey: "user")
}


Загрузка из UserDefaults
if let savedData = defaults.data(forKey: "user"),
let savedUser = try? JSONDecoder().decode(User.self, from: savedData) {
print(savedUser.name, savedUser.age) // Иван 25
}


🟠Удаление данных из `UserDefaults`
Чтобы удалить ключ:
defaults.removeObject(forKey: "user")


🟠Сохранение массива объектов
Можно сохранить массив объектов, просто закодировав его:
let users = [
User(name: "Иван", age: 25),
User(name: "Анна", age: 30)
]

if let encoded = try? JSONEncoder().encode(users) {
defaults.set(encoded, forKey: "users")
}

// Читаем массив обратно
if let savedData = defaults.data(forKey: "users"),
let savedUsers = try? JSONDecoder().decode([User].self, from: savedData) {
print(savedUsers) // [{name: Иван, age: 25}, {name: Анна, age: 30}]
}


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

Fetched Property — это динамическая связь, основанная на предопределённом запросе (fetch request). В отличие от обычных связей (relationship), она:
- не кешируется;
- выполняет отдельный запрос каждый раз при доступе;
- может фильтровать или выбирать связанные объекты по более сложным правилам.
Это полезно в случаях, когда нужно получить связанные данные по определённым условиям, но нужно учитывать, что производительность ниже, чем у обычной связи.


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

Это механизм в iOS/macOS для управления объектами, которые получают сообщение autorelease. Объекты добавляются в пул, и их память освобождается автоматически в конце выполнения блока, чтобы избежать утечек памяти. Используется для временных объектов.

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

Apple рекомендует использовать значимые типы (например, struct, enum) по следующим причинам:
- Они более предсказуемы, потому что копируются при передаче, и изменения в одной копии не затрагивают другие.
- Это упрощает многопоточность и предотвращает гонки данных.
- Swift делает копирование структур эффективным благодаря Copy-On-Write.
- Для UI и моделей данных это снижает количество неожиданных побочных эффектов.


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

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

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

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

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

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

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

Регулярное участие в собеседованиях (раз в полгода-год) помогает:
- держать навыки общения в тонусе;
- понимать ожидания рынка;
- адекватно оценивать свою стоимость;
- быть готовым к внезапным изменениям в работе.


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

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

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

Когда один объект (например, 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
🤔 Что такое enum, raw value и associated value в Swift?

Enum (перечисление) позволяет группировать связанные значения под общим типом с возможностью проверки типа. Raw value представляет постоянное значение каждого случая enum, например, строки или числа. Associated values позволяют хранить дополнительные пользовательские данные для каждого случая enum, поддерживая разные типы данных для разных случаев enum.

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

В iOS для выполнения фоновых задач существуют несколько ключевых механизмов:

🚩Основные механизмы

🟠Grand Central Dispatch (GCD): Используется для асинхронного выполнения задач на глобальных или пользовательских очередях.
DispatchQueue.global(qos: .background).async {
// Фоновая задача
}


🟠OperationQueue: Высокоуровневый API для управления очередями операций с возможностью указания зависимостей.
let queue = OperationQueue()
queue.addOperation {
// Фоновая операция
}


🟠Background Fetch: Позволяет приложению периодически загружать новые данные в фоновом режиме.
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Фоновое обновление данных
completionHandler(.newData)
}


🟠BGTaskScheduler: Новый фреймворк для планирования и выполнения фоновых задач.
import BackgroundTasks

func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.app.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
try? BGTaskScheduler.shared.submit(request)
}


🟠URLSession Background Transfers: Выполнение загрузки и выгрузки данных в фоновом режиме.
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app.background")
let session = URLSession(configuration: configuration)
let url = URL(string: "https://example.com/largefile")!
let task = session.downloadTask(with: url)
task.resume()


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

Подсчёт ссылок работает во время исполнения программы, в момент изменения количества strong-ссылок. Увеличивается при присваивании, уменьшается при обнулении или выходе из области видимости.


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

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

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

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

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

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

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

Стек (Stack) — это область памяти, которая используется для хранения локальных переменных и вызовов функций. Он организован по принципу LIFO (Last In, First Out), и данные в стеке автоматически освобождаются при завершении вызова функции. Куча (Heap) — это область памяти, используемая для динамического выделения памяти, где объекты хранятся до тех пор, пока на них существуют ссылки. В Swift объекты классов размещаются в куче, а структуры и примитивные типы — в стеке, что влияет на производительность и управление памятью.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🤔 Что происходит с параллельной очередью при запуске 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
💊2
🤔 Преимущества и недостатки синхронного и асинхронного соединения?

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


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