Swift | Вопросы собесов
2.14K subscribers
28 photos
957 links
Download Telegram
🤔 Какой тип у числа с плавающей точкой?

В большинстве языков — float, double, или Float32, Float64:
- float — 32 бита, ограниченная точность.
- double — 64 бита, выше точность и диапазон. Python использует тип float, который реализован как 64-битный IEEE 754 double.


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

Словарь (Dictionary) представляет собой коллекцию пар ключ-значение, где каждый ключ должен быть уникальным. Чтобы использовать какой-либо тип в качестве ключа словаря, этот тип должен соответствовать протоколу Hashable. Это требование обусловлено тем, что Swift использует хеш-таблицу для хранения элементов словаря, что обеспечивает быстрый доступ к его элементам.

🚩Ключи

Должны быть уникальными: Каждый ключ в словаре должен быть уникальным. При попытке добавить в словарь элемент с ключом, который уже существует в словаре, старое значение будет заменено на новое.
Должны соответствовать протоколу Hashable: Это означает, что тип ключа должен иметь способность быть правильно хешированным. Большинство базовых типов Swift (например, String, Int, Double и др.) уже соответствуют Hashable, поэтому их можно использовать в качестве ключей без дополнительных усилий.

🚩Значения

Могут быть любого типа: Значения в словаре могут быть любого типа, и они не обязаны соответствовать протоколу Hashable.
Могут повторяться: Разные ключи могут иметь одинаковые значения.
var personAge: [String: Int] = ["John": 30, "Sara": 25]


🚩Собственные типы в качестве ключей

Вы также можете использовать собственные пользовательские типы в качестве ключей словаря, но для этого ваш тип должен соответствовать протоколу Hashable. Это включает в себя реализацию требуемых методов для сравнения на равенство (==) и хеширования (hash(into:)).
struct Person: Hashable {
var name: String
var id: Int
}

var peopleDictionary: [Person: String] = [Person(name: "John", id: 1): "Engineer"]


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В чём разница между unowned и unowned(unsafe)?

- unowned — это слабая ссылка, но с гарантией, что объект ещё существует во время обращения. Если объект уже освобождён — произойдёт крах (crash).
- unowned(unsafe) — ещё менее безопасный вариант, не делает проверку на nil вообще. Это низкоуровневая, "сырой" доступ к памяти, использовать его нужно крайне осторожно.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
👍1
🤔 Что делает инициализация?

1. Инициализация устанавливает начальное состояние объекта, подготавливая его к использованию.
2. Включает выделение памяти и назначение значений свойствам (вручную или по умолчанию).
3. В Kotlin инициализация может выполняться через первичный конструктор, блоки init или вторичные конструкторы.


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

В 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
🤔 Чем отличается пассивная модель от активной?

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


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

В Swift есть несколько способов отлавливать и диагностировать ошибки в коде:

🚩Обработка ошибок через `do-catch`

Используется, если функция генерирует ошибку (throws).
enum LoginError: Error {
case wrongPassword
case userNotFound
}

func login(user: String, password: String) throws {
if user != "admin" { throw LoginError.userNotFound }
if password != "1234" { throw LoginError.wrongPassword }
}

do {
try login(user: "admin", password: "wrong")
} catch LoginError.wrongPassword {
print("Ошибка: Неверный пароль")
} catch {
print("Ошибка: \(error)")
}


🚩`assert()`, `precondition()`, `fatalError()` (для отладки)

Эти функции прерывают выполнение программы, если что-то пошло не так.
assert() (только в Debug)
let age = -5
assert(age >= 0, "Возраст не может быть отрицательным")


precondition() (работает в Release)
precondition(age >= 0, "Возраст не может быть отрицательным")


fatalError() (прерывает программу)
func getData() -> String {
fatalError("Метод ещё не реализован")
}


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

Closure захватывает value type по значению. То есть создаётся копия значения, и она остаётся доступной внутри замыкания, даже если оригинальное значение вышло из области видимости.


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

Метод `hitTest(_:with:)` в UIView используется для определения, какая вью была нажата пользователем. Он ищет самый глубокий (верхний) UI-элемент, который должен обработать касание.

🟠Если `isUserInteractionEnabled = false` (взаимодействие отключено)
Если у UIView выключено свойство isUserInteractionEnabled, то hitTest(_:with:) не будет работать – вью полностью игнорирует касания.
let button = UIButton()
button.isUserInteractionEnabled = false

let touchPoint = CGPoint(x: 50, y: 50)
let result = button.hitTest(touchPoint, with: nil)

print(result) // nil


🟠Если `alpha < 0.01` (вью почти прозрачна)
Если UIView почти полностью прозрачна (alpha меньше 0.01), то она не будет участвовать в обработке событий.
let view = UIView()
view.alpha = 0.005

let touchPoint = CGPoint(x: 50, y: 50)
let result = view.hitTest(touchPoint, with: nil)

print(result) // nil


🟠Если `isHidden = true` (вью скрыта)
Если вью скрыта (isHidden = true), hitTest(_:with:) не сработает, так как iOS её вообще не обрабатывает
let view = UIView()
view.isHidden = true

let touchPoint = CGPoint(x: 50, y: 50)
let result = view.hitTest(touchPoint, with: nil)

print(result) // nil


🟠Если точка касания за пределами `bounds` вью
hitTest(_:with:) проверяет только внутри `bounds` вью, и если точка находится за пределами, он вернёт `nil`.
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

let touchPoint = CGPoint(x: 150, y: 150) // Вне границ вью
let result = view.hitTest(touchPoint, with: nil)

print(result) // nil


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3💊2
🤔 Какая разница между Dependency Inversion и Dependency Injection?

Dependency Inversion — это принцип, согласно которому высокоуровневые модули не должны зависеть от низкоуровневых напрямую, а через абстракции. Dependency Injection — это механизм, с помощью которого зависимости передаются извне, реализуя этот принцип.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
👍1
🤔 Как optional хранится в памяти?

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

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

Да, отслеживание статуса задачи в DispatchWorkItem может быть полезным, но это зависит от требований приложения.

🟠Когда это полезно?
Если задача может быть отменена (cancel())
Если выполнение задачи можно приостановить или продолжить
Если нужно проверить завершение перед выполнением следующего действия*
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Запускаем задачу
DispatchQueue.global().async(execute: workItem)

// Отмена перед выполнением
workItem.cancel()

// Проверяем статус выполнения
if workItem.isCancelled {
print("Задача отменена")
} else {
print("Задача выполнена")
}


🟠Можно ли проверить, завершена ли задача?
В DispatchWorkItem нет метода проверки завершения.
Но можно вручную отслеживать завершение с помощью notify:
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Сообщаем о завершении
workItem.notify(queue: .main) {
print("Задача завершена")
}

DispatchQueue.global().async(execute: workItem)


🟠Надо ли всегда отслеживать статус?
Если задача короткая и простая → НЕ ОБЯЗАТЕЛЬНО.
Если задача важная, может быть отменена или зависит от других задач → ЛУЧШЕ ОТСЛЕЖИВАТЬ.

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

Нужно выносить бизнес-логику в модель, а форматирование данных — во вью-модель или presenter. Контроллер должен только координировать взаимодействие между этими слоями.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Для каких сущностей работает 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
👍1
🤔 При каких условиях счётчик уменьшается?

Счётчик ссылок (ARC) уменьшается, когда ссылка на объект уничтожается, т.е. когда переменная, содержащая ссылку, выходит из области видимости или явно устанавливается в nil.


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

CocoaPods — это менеджер зависимостей для проектов iOS/macOS. Он позволяет подключать сторонние библиотеки в проект, управлять их версиями, устанавливать и обновлять автоматически.


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

Apple предпочитает value types (структуры struct) по умолчанию в Swift по нескольким причинам

🟠Безопасность многопоточного кода
struct копируется при передаче, а не передается по ссылке, как class.
Это снижает вероятность гонки данных (data race), когда один поток изменяет объект, а другой читает его одновременно.
В многопоточной среде это делает код более безопасным.
struct Point {
var x: Int
var y: Int
}

var p1 = Point(x: 1, y: 2)
var p2 = p1 // p2 - это копия, изменения в p2 не затронут p1

p2.x = 10

print(p1.x) // 1
print(p2.x) // 10


🟠Производительность
struct хранятся в стеке, а не в куче, что делает их создание и удаление быстрее.
Куча (heap) требует управления памятью (ARC – Automatic Reference Counting), а struct — нет.
class MyClass { var value = 0 }  // В куче (heap), управляется ARC
struct MyStruct { var value = 0 } // В стеке (stack), копируется при передаче


🟠Предсказуемость и неизменяемость
struct ведут себя как примитивные типы (Int, Double), что делает код предсказуемым.
Их изменение происходит локально, без неожиданных эффектов в других частях программы.
class Car {
var speed: Int
init(speed: Int) { self.speed = speed }
}

var car1 = Car(speed: 60)
var car2 = car1 // car2 - это ссылка на тот же объект

car2.speed = 100 // Изменение затрагивает car1!

print(car1.speed) // 100 (хотя мы меняли car2!)


🟠Использование в стандартной библиотеке
Swift изначально построен на struct:
Int, Double, Bool, Array, Dictionary, String — это структуры.
Это делает язык более безопасным и производительным.
var arr1 = [1, 2, 3]
var arr2 = arr1 // Копия массива, а не ссылка!

arr2.append(4)

print(arr1) // [1, 2, 3] (не изменился!)
print(arr2) // [1, 2, 3, 4] (новый массив)


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

Хотя struct — предпочтительный выбор, class нужен, когда:
Нужна ссылочная семантика (например, объект должен изменяться в разных местах кода).
Есть сложные иерархии наследования.
Требуется работа с Objective-C (NSObject).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3