Swift | Вопросы собесов
2.13K subscribers
28 photos
947 links
Download Telegram
📌 Что будет, если убрать опционал из свифта?

💬 Спрашивают в 18% собеседований

Если убрать опционалы из Swift, это приведет к значительным изменениям в языке и его поведении, что окажет влияние на несколько ключевых аспектов программирования:

1️⃣ Обработка отсутствующих значений

Сейчас: Опционалы позволяют явно указать, что переменная может не иметь значения (nil). Это помогает избежать неожиданных ошибок и делает код более безопасным.
     var name: String? = nil
if let unwrappedName = name {
print("Name is \(unwrappedName)")
} else {
print("Name is nil")
}


Без опционалов: При отсутствии опционалов переменные всегда должны иметь значение. Это приведет к необходимости использования значений по умолчанию или специальным образом обозначать отсутствие значения.
     var name: String = "" // Значение по умолчанию
if name.isEmpty {
print("Name is nil")
} else {
print("Name is \(name)")
}


2️⃣ Безопасность и стабильность кода

Сейчас: Опционалы снижают вероятность возникновения ошибок типа "null pointer exception" (ошибок доступа к пустым указателям), заставляя программиста явно проверять и обрабатывать nil.

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

3️⃣ Упрощение синтаксиса

Сейчас: Использование опционалов добавляет некоторую сложность в синтаксис, требуя использования операторов ?, !, if let и guard let.

Без опционалов: Синтаксис станет проще, но за счет потери явного указания на возможность отсутствия значения, что может привести к ошибкам, связанным с предположением о существовании значений.

4️⃣ Обработка ошибок

Сейчас: Опционалы часто используются для обработки ошибок, когда метод может вернуть nil в случае неудачи.
     func findUser(byID id: Int) -> User? {
// Возвращает nil, если пользователь не найден
}


Без опционалов: Придется использовать альтернативные подходы для обработки ошибок, например, бросание исключений или использование специальных объектов-обёрток.
     func findUser(byID id: Int) -> User {
// Возвращает пустого пользователя или значение по умолчанию
return User()
}


5️⃣ Совместимость с Objective-C

Сейчас: Опционалы позволяют легко интегрироваться с Objective-C, где значения могут быть nil.

Без опционалов: Совместимость с Objective-C станет сложнее, поскольку в Objective-C многие методы могут возвращать nil.

🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой оператор Swift используется для безопасного извлечения значений из опциональных типов?
Anonymous Quiz
9%
`!`
54%
`?`
33%
`??`
5%
`->`
📌 Что такое мьютекс (mutex)?

💬 Спрашивают в 18% собеседований

Мьютекс (от англ. "mutex" - mutual exclusion, взаимное исключение) — это механизм синхронизации, используемый в многопоточном программировании для предотвращения одновременного доступа нескольких потоков к общим ресурсам, таким как переменные, структуры данных или файлы. Он помогает избежать состояния гонки (race condition), когда результат выполнения программы зависит от неопределённого порядка доступа потоков к ресурсу.

🤔 Основные концепции мьютекса

1️⃣ Взаимное исключение:

Мьютекс обеспечивает доступ к общему ресурсу только одному потоку в каждый момент времени.

Когда один поток захватывает мьютекс, другие потоки должны ждать, пока мьютекс не будет освобождён.

2️⃣ Захват и освобождение:

Поток захватывает мьютекс перед доступом к общему ресурсу и освобождает его после завершения работы с этим ресурсом.

Если мьютекс уже захвачен другим потоком, текущий поток будет блокирован до тех пор, пока мьютекс не будет освобождён.

🤔 Пример использования мьютекса в Swift

В Swift можно использовать класс NSLock для создания мьютексов:
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())")


🤔 Преимущества использования мьютексов

1️⃣ Безопасность данных:

Мьютексы защищают общие ресурсы от одновременного доступа, предотвращая повреждение данных.

2️⃣ Предсказуемость:

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

Недостатки использования мьютексов

1️⃣ Мёртвые блокировки (Deadlocks):

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

2️⃣ Производительность:

Чрезмерное использование мьютексов может привести к снижению производительности из-за увеличения времени ожидания потоков.

🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В Swift, какое ключевое слово используется для обозначения переменной, которая не будет изменяться после её инициализации?
Anonymous Quiz
7%
var
2%
const
84%
let
8%
fix
📌 Как можно оптимизировать выполнение кода в Swift?

💬 Спрашивают в 18% собеседований

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

1️⃣ Использование правильных структур данных

Array vs. Set vs. Dictionary: Выбирайте структуру данных в зависимости от задачи. Например, для уникальных элементов и быстрого поиска используйте Set, для пар ключ-значение — Dictionary.
   var array = [1, 2, 3, 4, 5]
var set: Set = [1, 2, 3, 4, 5]
var dictionary = ["one": 1, "two": 2, "three": 3]


2️⃣ Минимизация использования опционалов

Избегайте чрезмерного использования опционалов и принудительного разворачивания, так как это может снижать производительность и приводить к ошибкам.
   var name: String? = "John"
if let unwrappedName = name {
print("Name is \(unwrappedName)")
}


3️⃣ Избегание ненужного копирования

Используйте inout параметры для избежания копирования при передаче значений в функции.
   func increment(value: inout Int) {
value += 1
}
var number = 1
increment(value: &number)


4️⃣ Профилирование и отладка

Используйте инструменты профилирования, такие как Instruments, для анализа производительности и выявления узких мест.

5️⃣ Асинхронность и параллелизм

Используйте GCD (Grand Central Dispatch) и OperationQueue для выполнения задач в фоновом режиме.
   DispatchQueue.global(qos: .background).async {
// Фоновая задача
DispatchQueue.main.async {
// Обновление UI на главном потоке
}
}


6️⃣ Lazy Loading

Используйте ленивую загрузку для отложенной инициализации свойств до момента их первого использования.
   class MyClass {
lazy var expensiveObject: ExpensiveObject = {
return ExpensiveObject()
}()
}


7️⃣ Избегание ненужных вычислений

Кэшируйте результаты дорогостоящих вычислений.
   var cache = [Int: Int]()
func fibonacci(_ n: Int) -> Int {
if let result = cache[n] {
return result
}
if n <= 1 { return n }
let result = fibonacci(n - 1) + fibonacci(n - 2)
cache[n] = result
return result
}


8️⃣ Оптимизация циклов

Используйте эффективные конструкции циклов и избегайте лишних операций внутри них.
   for i in 0..<1000 {
// Оптимизированный код
}


9️⃣ Использование Value Types

Структуры (value types) могут быть более эффективными, чем классы (reference types), особенно для небольших объектов.
   struct Point {
var x: Int
var y: Int
}


1️⃣0️⃣ Избегание глобальных переменных

Глобальные переменные могут приводить к снижению производительности и трудностям с отладкой.

🤔 Заключение

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

В двух фразах: Оптимизировать выполнение кода в Swift можно с помощью правильного выбора структур данных, асинхронного выполнения задач, ленивой загрузки и кэширования результатов. Профилирование помогает выявить и устранить узкие места в производительности.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
📌 Почему swift не может сам сгенерировать memberwise инициализатор для классов?

💬 Спрашивают в 18% собеседований

В Swift автоматически генерируемый memberwise инициализатор доступен только для структур (structs), но не для классов (classes). Это связано с рядом различий между этими двумя типами и некоторыми особенностями их поведения.

🤔 Причины отсутствия автоматического memberwise инициализатора для классов

1️⃣ Наследование

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

Пример:
     class BaseClass {
var baseProperty: String
init(baseProperty: String) {
self.baseProperty = baseProperty
}
}

class SubClass: BaseClass {
var subProperty: Int
init(baseProperty: String, subProperty: Int) {
self.subProperty = subProperty
super.init(baseProperty: baseProperty)
}
}


2️⃣ Инициализаторы и деинициализаторы

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

Пример:
     class ResourceHandler {
var resource: Resource

init(resource: Resource) {
self.resource = resource
// Дополнительные действия по настройке ресурса
}

deinit {
// Освобождение ресурса
}
}


3️⃣ Объекты с ссылочными типами (Reference Types)

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

Пример:
     class Node {
var value: Int
var next: Node?

init(value: Int, next: Node?) {
self.value = value
self.next = next
}
}


4️⃣ Пользовательские требования к инициализации

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

Пример:
     class User {
var name: String
var age: Int

init(name: String, age: Int) {
guard age > 0 else {
fatalError("Возраст должен быть положительным")
}
self.name = name
self.age = age
}
}


🤔 Заключение

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

В двух фразах: Swift не генерирует memberwise инициализаторы для классов из-за сложности, связанной с наследованием и управлением памятью, а также необходимости учитывать специфические требования к инициализации. Разработчики должны явно определять инициализаторы для обеспечения корректной работы классов.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой модификатор доступа позволяет использовать переменную только внутри текущего модуля?
Anonymous Quiz
36%
private
15%
fileprivate
46%
internal
3%
public
📌 Что такое runLoop?

💬 Спрашивают в 18% собеседований

RunLoop — это фундаментальный механизм в iOS и macOS, который управляет циклом обработки событий в приложении. Он отслеживает и обрабатывает входящие события, такие как нажатия клавиш, касания экрана, таймеры и сетевые запросы, и поддерживает приложение в активном состоянии, пока оно не завершится.

🤔 Основные аспекты `RunLoop`

1️⃣ Цикл обработки событий

RunLoop постоянно выполняет цикл, ожидая входящие события и обрабатывая их по мере поступления. Этот цикл состоит из нескольких этапов: ожидание события, обработка события и повтор цикла.

2️⃣ Режимы (Modes)

RunLoop может работать в разных режимах, которые определяют, какие источники событий будут отслеживаться и обрабатываться. Основные режимы включают default и tracking (для событий отслеживания, таких как прокрутка). В каждой итерации RunLoop обрабатывает события только для текущего режима.

Пример:
     RunLoop.current.run(mode: .default, before: Date.distantFuture)


3️⃣ Источники событий (Event Sources)

RunLoop может отслеживать различные источники событий, такие как таймеры (Timer), порты (Port), ввод пользователей (такие как касания экрана и клики мыши), а также пользовательские источники (Input Source).

4️⃣ Таймеры

RunLoop может управлять таймерами, которые выполняют задачи через определенные интервалы времени.

Пример:
     let timer = Timer(timeInterval: 1.0, repeats: true) { _ in
print("Timer fired!")
}
RunLoop.current.add(timer, forMode: .default)


5️⃣ Обработка событий

RunLoop используется для обработки событий в основном потоке (main thread) приложения. Это особенно важно для поддержания отзывчивости пользовательского интерфейса, поскольку все взаимодействия с UI происходят в основном потоке.

🤔 Пример использования `RunLoop`
import Foundation

class Example {
var timer: Timer?

func startRunLoop() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
RunLoop.current.run()
}

@objc func timerFired() {
print("Timer fired!")
}
}

let example = Example()
example.startRunLoop()


🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
📌 Что такое rsi?

💬 Спрашивают в 18% собеседований

RSI может обозначать разные вещи в зависимости от контекста, но наиболее часто эта аббревиатура используется в следующих двух областях:

1️⃣ Relative Strength Index (RSI) в финансах
Relative Strength Index (RSI) — это технический индикатор, используемый в анализе финансовых рынков для оценки силы и скорости изменения цен актива. RSI помогает определить перекупленность или перепроданность актива, что может указывать на возможность коррекции цены или разворота тренда.

🤔 Основные аспекты RSI:

Расчет RSI:

RSI обычно рассчитывается на основе 14 последних периодов (дней, часов и т. д.) и колеблется в диапазоне от 0 до 100.

Формула RSI:
\[
RSI = 100 - \left(\frac{100}{1 + RS}\right)
\]
где RS (Relative Strength) = среднее значение закрытия вверх / среднее значение закрытия вниз.

Интерпретация RSI:

Значение RSI выше 70 может указывать на перекупленность актива, что означает, что цена может снизиться.

Значение RSI ниже 30 может указывать на перепроданность актива, что означает, что цена может вырасти.

Использование RSI:

RSI часто используется трейдерами и аналитиками для принятия решений о покупке или продаже актива.

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

🤔 Пример использования RSI:
import Foundation

// Пример функции для расчета RSI на Swift
func calculateRSI(prices: [Double]) -> Double? {
guard prices.count >= 14 else { return nil }

let averageGain = prices[1..<14].filter { $0 >= 0 }.reduce(0, +) / 14
let averageLoss = prices[1..<14].filter { $0 < 0 }.reduce(0, +).magnitude / 14

guard averageLoss != 0 else { return 100 }

let rs = averageGain / averageLoss
let rsi = 100 - (100 / (1 + rs))

return rsi
}

let prices = [1.1, 1.2, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7]
if let rsi = calculateRSI(prices: prices) {
print("RSI: \(rsi)")
}


2️⃣ Repetitive Strain Injury (RSI) в медицине

Repetitive Strain Injury (RSI) — это медицинский термин, обозначающий травмы, возникающие в результате повторяющихся движений или чрезмерного использования определенных частей тела, обычно рук и кистей. RSI часто встречается у людей, работающих за компьютером, музыкантов, спортсменов и тех, кто выполняет повторяющиеся физические задачи.

🤔 Основные аспекты RSI:

Причины RSI:

Длительное использование клавиатуры и мыши без перерывов.

Неправильная осанка и неподходящее рабочее место.

Повторяющиеся физические движения или стресс на определенные части тела.

Симптомы RSI:

Боль, дискомфорт или слабость в мышцах и суставах.

Ощущение онемения или покалывания.

Ограниченная подвижность или скованность в пораженной области.

🤔 Профилактика и лечение RSI:

Регулярные перерывы и изменение позы.

Правильная организация рабочего места.

Упражнения для растяжки и укрепления мышц.

Медицинское лечение, включая физиотерапию и противовоспалительные препараты.

🤔 Пример профилактики RSI:

Настройте рабочее место, чтобы монитор был на уровне глаз.

Используйте эргономичную клавиатуру и мышь.

Делайте перерывы каждые 30 минут для разминки и изменения позы.

🤔 Заключение:

RSI может означать как технический индикатор Relative Strength Index в финансах, так и медицинское состояние Repetitive Strain Injury. В финансах RSI помогает анализировать состояние рынка, в то время как в медицине RSI относится к травмам, вызванным повторяющимися движениями.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯8👀3
🤔 Какой оператор используется для безопасного извлечения значения из Optional?
Anonymous Quiz
62%
?
4%
!
32%
??
1%
@
😁20🤯1
📌 Зачем нужен словарь?

💬 Спрашивают в 18% собеседований

Словарь (dictionary) в программировании — это структура данных, которая хранит пары ключ-значение. В Swift словарь представлен типом Dictionary<K, V>, где K — это тип ключей, а V — тип значений. Словари широко используются из-за их эффективности и удобства. Вот основные причины и примеры использования словарей:

🤔 Основные причины использования словарей

1️⃣ Быстрый доступ к данным

Словари обеспечивают быстрый доступ к значениям по ключам, обычно с постоянным временем доступа O(1). Это делает их идеальными для ситуаций, когда нужно часто искать данные по известным ключам.
   var phoneBook: [String: String] = ["Alice": "123-4567", "Bob": "987-6543"]
if let number = phoneBook["Alice"] {
print("Alice's phone number is \(number)")
}


2️⃣ Уникальные ключи

Ключи в словаре уникальны, что позволяет легко управлять данными, предотвращая дублирование ключей и обеспечивая целостность данных.
   var inventory: [String: Int] = ["Apples": 10, "Bananas": 5]
inventory["Apples"] = 15 // Обновление количества яблок


3️⃣ Гибкость и удобство

Словари могут хранить значения любых типов, включая пользовательские типы, что делает их гибкими для различных применений.
   struct Person {
let name: String
let age: Int
}

var people: [String: Person] = ["Alice": Person(name: "Alice", age: 30), "Bob": Person(name: "Bob", age: 25)]
if let person = people["Alice"] {
print("\(person.name) is \(person.age) years old")
}


4️⃣ Группировка связанных данных

Словари позволяют логически группировать связанные данные, облегчая управление и обработку этих данных.
   var studentGrades: [String: [String: Double]] = [
"Alice": ["Math": 95, "Science": 90],
"Bob": ["Math": 85, "Science": 80]
]
if let aliceGrades = studentGrades["Alice"] {
print("Alice's Math grade is \(aliceGrades["Math"] ?? 0)")
}


5️⃣ Использование в алгоритмах и структурах данных

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

Хранение данных о студентах
var students: [Int: String] = [101: "Alice", 102: "Bob", 103: "Charlie"]
if let student = students[102] {
print("Student with ID 102 is \(student)")
}


Подсчет частоты элементов
let words = ["apple", "banana", "apple", "orange", "banana", "apple"]
var wordCount: [String: Int] = [:]

for word in words {
wordCount[word, default: 0] += 1
}

print(wordCount) // ["apple": 3, "banana": 2, "orange": 1]


🤔 Настройки приложения
var settings: [String: Any] = ["theme": "dark", "notificationsEnabled": true]
if let theme = settings["theme"] as? String {
print("Current theme is \(theme)")
}


🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
📌 Что такое final?

💬 Спрашивают в 18% собеседований

В Swift, final — это ключевое слово, используемое для предотвращения наследования от класса или переопределения его методов и свойств. Когда вы объявляете класс или его члены с помощью final, вы говорите компилятору, что этот класс или члены не должны быть изменены или расширены.

🤔 Основные применения `final`

1️⃣ Запрет на наследование класса

Когда класс объявлен как final, его нельзя использовать в качестве базового класса для создания подклассов.

Пример:
final class Animal {
var name: String

init(name: String) {
self.name = name
}
}

// Попытка создать подкласс от final-класса вызовет ошибку компиляции
// class Dog: Animal { }


2️⃣ Запрет на переопределение методов

Методы, объявленные как final, не могут быть переопределены в подклассах.

Пример:
     class Vehicle {
final func startEngine() {
print("Engine started")
}
}

class Car: Vehicle {
// Попытка переопределить метод вызовет ошибку компиляции
// override func startEngine() {
// print("Car engine started")
// }
}


3️⃣ Запрет на переопределение свойств

Свойства, объявленные как final, не могут быть переопределены в подклассах.

Пример:
     class Building {
final var numberOfFloors: Int {
return 5
}
}

class Skyscraper: Building {
// Попытка переопределить свойство вызовет ошибку компиляции
// override var numberOfFloors: Int {
// return 100
// }
}


🤔 Преимущества использования `final`

1️⃣ Улучшение производительности

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

2️⃣ Улучшение безопасности кода

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

3️⃣ Ясность намерений

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

🤔 Заключение:

Ключевое слово final в Swift используется для предотвращения наследования классов и переопределения методов и свойств. Это улучшает производительность, безопасность кода и делает намерения разработчика более явными.

В двух фразах: final предотвращает наследование классов и переопределение методов и свойств, улучшая производительность и безопасность кода. Это делает код более предсказуемым и понятным.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
1
📌 В чём разница между вью и леером?

💬 Спрашивают в 18% собеседований

В iOS и macOS приложениях, разработанных с использованием Swift или Objective-C, UIView и CALayer играют ключевые роли в управлении и отображении пользовательского интерфейса. Несмотря на то, что они тесно связаны, между ними есть важные различия. Давайте рассмотрим их подробнее.

🤔 UIView

1️⃣ Описание:

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

2️⃣ Основные свойства и методы:

UIView предоставляет множество свойств и методов для управления внешним видом, положением и поведением представления. Примеры включают frame, bounds, center, backgroundColor, alpha, isHidden, и subviews.

UIView также поддерживает анимации, автолэйаут и работу с событийной системой.

3️⃣ Реакция на события:

UIView обрабатывает пользовательские события, такие как касания и жесты. Он предоставляет методы, такие как touchesBegan, touchesMoved, и touchesEnded, для обработки этих событий.

4️⃣ Пример использования:
   let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myView.backgroundColor = .blue
view.addSubview(myView)


🤔 CALayer

1️⃣ Описание:

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

2️⃣ Основные свойства и методы:

CALayer предоставляет свойства для управления внешним видом, такими как backgroundColor, borderWidth, cornerRadius, shadowOpacity, contents (для отображения изображений), и transform.

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

3️⃣ Реакция на события:

CALayer не обрабатывает пользовательские события напрямую. Эти задачи оставлены на UIView, который может содержать один или несколько слоев.

   let myLayer = CALayer()
myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myLayer.backgroundColor = UIColor.blue.cgColor
view.layer.addSublayer(myLayer)


🤔 Основные различия между UIView и CALayer

1️⃣ По уровеню абстракции:

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

2️⃣ Реакция на события:

UIView
обрабатывает события пользовательского интерфейса.

CALayer не обрабатывает события, но предоставляет возможности для рендеринга и анимации.

3️⃣ Иерархия:

UIView может содержать другие представления (subviews) и управлять их иерархией.

CALayer может содержать другие слои (sublayers) и управлять их иерархией.

4️⃣ Анимации:

UIView использует UIView.animate для создания анимаций, которые высокоуровневые и просты в использовании.

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

🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Когда value type может храниться в куче?

💬 Спрашивают в 18% собеседований

В Swift, типы значений (value types) обычно хранятся в стеке, что обеспечивает их высокую производительность и простоту управления памятью. Однако в некоторых случаях типы значений могут храниться в куче (heap). Это может происходить в следующих ситуациях:

1️⃣ Захват в замыкании (Closure Capture)

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

Пример:
struct MyStruct {
var value: Int
}

func createClosure() -> () -> Int {
let myStruct = MyStruct(value: 42)
return { myStruct.value }
}

let closure = createClosure()
print(closure()) // Output: 42


В этом примере myStruct захватывается замыканием, что приводит к его размещению в куче.

2️⃣ Использование класса-контейнера (Boxing)

Иногда для хранения типов значений в куче используется техника "boxing". Это означает, что значение типа заворачивается в объект класса, который хранится в куче.

Пример:
class Box<T> {
var value: T
init(_ value: T) {
self.value = value
}
}

struct MyStruct {
var value: Int
}

let boxedStruct = Box(MyStruct(value: 42))
print(boxedStruct.value.value) // Output: 42


Здесь структура MyStruct обернута в объект класса Box, что приводит к её размещению в куче.

3️⃣ Свойства классов

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

Пример:
struct MyStruct {
var value: Int
}

class MyClass {
var myStruct: MyStruct
init(myStruct: MyStruct) {
self.myStruct = myStruct
}
}

let instance = MyClass(myStruct: MyStruct(value: 42))
// instance.myStruct хранится в куче


В этом примере структура MyStruct является свойством класса MyClass, поэтому её экземпляры хранятся в куче вместе с экземплярами MyClass.

4️⃣ Коллекции, содержащие типы значений

Коллекции, такие как массивы, словари и множества, хранящие типы значений, могут размещать эти значения в куче, если коллекция становится слишком большой.

Пример:
struct MyStruct {
var value: Int
}

let array = [MyStruct(value: 1), MyStruct(value: 2), MyStruct(value: 3)]
// Элементы массива могут быть размещены в куче


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

🤔 Заключение

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1
🤔 Какой тип коллекции в Swift неупорядочен?
Anonymous Quiz
9%
Array
69%
Set
18%
Dictionary
5%
Tuple
🤯4👍2
📌 Чем отличаются слабые и сильные ссылки?

💬 Спрашивают в 18% собеседований

В Swift ссылки (references) на объекты могут быть сильными (strong) и слабыми (weak). Они отличаются способом управления памятью и временем жизни объектов, на которые ссылаются.

🤔 Сильные ссылки (Strong References)

Описание: Сильная ссылка (strong reference) удерживает объект в памяти. Пока существует хотя бы одна сильная ссылка на объект, он не будет удалён из памяти.

Применение: Сильные ссылки используются по умолчанию и обеспечивают, что объект остаётся доступным до тех пор, пока он необходим.

🤔 Пример использования:
class Person {
var name: String
init(name: String) {
self.name = name
}
}

var person1: Person? = Person(name: "Alice")
var person2: Person? = person1 // person2 имеет сильную ссылку на тот же объект, что и person1

person1 = nil // Объект все еще удерживается в памяти благодаря person2
print(person2?.name) // Output: Alice

person2 = nil // Теперь объект будет удалён из памяти, так как нет сильных ссылок


🤔 Слабые ссылки (Weak References)

Описание: Слабая ссылка (weak reference) не удерживает объект в памяти. Если объект больше не имеет сильных ссылок, он будет удалён из памяти, даже если на него существуют слабые ссылки.

Применение: Слабые ссылки используются для предотвращения циклических ссылок, которые могут привести к утечкам памяти.

🤔 Пример использования:
class Person {
var name: String
init(name: String) {
self.name = name
}
}

class Apartment {
var tenant: Person?
init(tenant: Person?) {
self.tenant = tenant
}
}

var alice: Person? = Person(name: "Alice")
var apartment: Apartment? = Apartment(tenant: alice)

// Создание слабой ссылки для предотвращения циклической зависимости
class Tenant {
var name: String
weak var apartment: Apartment? // Слабая ссылка
init(name: String) {
self.name = name
}
}

let tenant = Tenant(name: "Bob")
apartment?.tenant = alice

alice = nil // Объект Person будет удалён из памяти, так как больше нет сильных ссылок
print(apartment?.tenant?.name) // Output: nil


🤔 Основные различия между сильными и слабыми ссылками

1️⃣ Удержание в памяти:

Сильные ссылки: Удерживают объект в памяти. Объект будет освобождён только тогда, когда все сильные ссылки на него будут удалены.

Слабые ссылки: Не удерживают объект в памяти. Объект будет освобождён, когда не останется сильных ссылок.

2️⃣ Использование:

Сильные ссылки: Используются по умолчанию для обеспечения сохранности объектов в памяти.

Слабые ссылки: Используются для предотвращения циклических ссылок и утечек памяти, особенно в структурах данных с взаимосвязанными объектами.

3️⃣ Обнуление:

Сильные ссылки: Не обнуляются автоматически при удалении объекта из памяти.

Слабые ссылки: Автоматически обнуляются, когда объект, на который они ссылаются, удаляется из памяти.

🤔 Заключение

Сильные и слабые ссылки в Swift различаются по способу управления памятью и временем жизни объектов. Сильные ссылки удерживают объекты в памяти, тогда как слабые ссылки позволяют объектам быть удалёнными, предотвращая циклические ссылки и утечки памяти.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2