Swift | Вопросы собесов
2.13K subscribers
28 photos
939 links
Download Telegram
📌 Каков жизненный цикл приложения ?

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

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

1️⃣ Не запущено (Not Running)

Приложение ещё не было запущено или было завершено.

2️⃣ Неактивное состояние (Inactive)

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

3️⃣ Активное состояние (Active)
Приложение активно и получает события. Это основное рабочее состояние приложения, когда пользователь взаимодействует с его интерфейсом.

4️⃣ Фоновое состояние (Background)

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

5️⃣ Приостановлено (Suspended)

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

Методы AppDelegate для управления жизненным циклом

Разработчики могут реагировать на изменения в жизненном цикле, используя методы делегата UIApplicationDelegate, такие как:

application(_:didFinishLaunchingWithOptions:) — вызывается, когда приложение завершает запуск.

applicationDidBecomeActive(_:) — вызывается, когда приложение становится активным.

applicationWillResignActive(_:) — вызывается, когда приложение переходит из активного состояния в неактивное.

applicationDidEnterBackground(_:) — вызывается, когда приложение переходит в фоновый режим.

applicationWillEnterForeground(_:) — вызывается перед переходом приложения из фонового режима в активный.

applicationWillTerminate(_:) — вызывается перед тем, как приложение будет завершено.

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как в Swift создать массив, который может изменяться после создания?
Anonymous Quiz
1%
let array = [Int]()
95%
var array = [Int]()
1%
const array = [Int]()
3%
array<int> = []
📌 Что такое "Опционалы" ?

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

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

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

🤔 Пример:
var optionalInt: Int? = nil


В этом случае переменная optionalInt объявлена как опциональная Int. Изначально она не содержит значения, что обозначается как nil.

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

1️⃣ Принудительное развертывание: Использование восклицательного знака (!) для доступа к значению опционала. Этот метод опасен, так как может привести к ошибке времени выполнения, если опционал содержит nil.
let someValue: Int? = 5
let unwrappedValue: Int = someValue! // Принудительное развертывание


2️⃣ Опциональное связывание: Позволяет безопасно проверить и извлечь значение опционала, если оно существует.
if let unwrappedValue = someValue {
print(unwrappedValue) // Безопасное использование unwrappedValue
}


3️⃣ Оператор объединения с nil (nil-coalescing operator): Позволяет предоставить значение по умолчанию для опционала в случае, если в нем содержится nil.
let defaultValue = someValue ?? 0 // Использует 0, если someValue содержит nil


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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой оператор в Swift используется для безопасного разыменования опционалов?
Anonymous Quiz
48%
`?`
4%
`!`
47%
`??`
1%
`&`
🤔1
📌 В чем разница между MVC и MVVM ?

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

MVC (Model-View-Controller) и MVVM (Model-View-ViewModel) — это два популярных архитектурных паттерна, используемых в разработке ПО для организации кода и разделения ответственности между компонентами системы. Оба паттерна направлены на упрощение разработки и поддержки приложений, но они делают это по-разному.

🤔 MVC (Model-View-Controller) Компоненты:

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

View: Отображает данные (модель) пользователю и отправляет действия пользователя контроллеру. View не содержит бизнес-логику обработки данных.

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

🤔 Особенности:

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

🤔 MVVM (Model-View-ViewModel) Компоненты:

Model: Содержит данные и бизнес-логику.

View: Отображает визуальные элементы и генерирует события пользовательского ввода. View также может непосредственно обращаться к ViewModel через привязку данных (data binding).

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

🤔 Особенности:

Слабая связь между View и ViewModel, что упрощает тестирование и поддержку.

Использование привязки данных сокращает объём шаблонного кода для обновления интерфейса.

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

Связность: В MVVM меньше связности между отображением и логикой представления, благодаря использованию ViewModel и механизмов привязки данных. В MVC виды и контроллеры тесно связаны.

Разделение ответственности: MVVM позволяет лучше разделить логику отображения от бизнес-логики, переместив большую часть логики отображения из View в ViewModel. В MVC контроллеры могут стать перегруженными, поскольку в них содержится и логика управления данными, и логика управления представлениями.

Тестирование: MVVM облегчает тестирование логики представления благодаря слабой связности и отделению ViewModel от View. В MVC тестирование может быть усложнено из-за сильной связности между контроллерами и видами.

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Какая функция используется для печати в консоль в Swift?
Anonymous Quiz
95%
print()
2%
println()
0%
echo()
2%
console.log()
👾1
📌 Что такое Retain Cycle ?

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

Цикл удержания (Retain Cycle) — это проблема управления памятью, которая возникает в языках программирования с автоматическим подсчётом ссылок (например, в Swift и Objective-C), когда два объекта хранят сильные (strong) ссылки друг на друга. Это приводит к тому, что объекты не освобождаются автоматически после того, как становятся ненужными, потому что счетчик ссылок на каждый из них остаётся больше нуля. В результате память, которую занимают эти объекты, утекает, что может привести к избыточному расходу памяти и в конечном итоге к снижению производительности или даже к аварийному завершению работы приложения.

🤔 Как оно возникает

Представьте себе два объекта A и B. Объект A имеет сильную ссылку на объект B, а объект B в свою очередь имеет сильную ссылку на объект A. В такой ситуации, даже если внешние ссылки на эти объекты будут удалены, они всё равно не будут освобождены из-за взаимных сильных ссылок, которые поддерживают счетчик ссылок каждого из объектов больше нуля.

🤔 Как избежать этого

1️⃣ Использование слабых (weak) или некрепких (unowned) ссылок: Одним из решений является использование слабых или некрепких ссылок для одного из взаимосвязанных объектов.weak и unowned ссылки не увеличивают счетчик ссылок объекта, на который они указывают, что предотвращает возникновение цикла удержания.

Слабые ссылки (`weak`): Используются, когда ссылка может быть nil. Swift автоматически обнуляет слабую ссылку, когда объект, на который она указывает, освобождается.

Некрепкие ссылки (`unowned`): Используются, когда гарантировано, что ссылка всегда будет указывать на объект, и вы хотите избежать цикла удержания. В отличие от слабой ссылки, некрепкая ссылка не обнуляется автоматически и может привести к ошибке времени выполнения, если объект будет освобождён.

2️⃣Изменение архитектуры приложения: Иногда стоит пересмотреть взаимодействие между объектами в вашем приложении, чтобы избежать необходимости создания взаимосильных ссылок.

🤔 Пример:
class Parent {
var child: Child?
}

class Child {
weak var parent: Parent?
}

var parent: Parent? = Parent()
var child: Child? = Child()

parent?.child = child
child?.parent = parent

// Разрыв ссылок
parent = nil
child = nil


В этом примере parent имеет сильную ссылку на child, но child имеет слабую ссылку на parent. Это предотвращает возникновение цикла удержания, и объекты могут быть корректно освобождены из памяти.

Цикл удержания — это ситуация, при которой два объекта ссылаются друг на друга сильными ссылками, предотвращая их освобождение и вызывая утечку памяти. Использование слабых (weak) или некрепких (unowned) ссылок помогает избежать этих циклов и обеспечивает корректное управление памятью в приложениях на Swift и Objective-C.

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какое ключевое слово в Swift определяет переменную, значение которой не может быть изменено после установки?
Anonymous Quiz
11%
var
84%
let
3%
const
1%
static
📌 Как устроен responder chain ?

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

Responder chain (цепочка обработчиков событий) — это концепция, используемая для обработки событий, таких как касания, жесты, нажатия клавиш и другие пользовательские действия. Она представляет собой последовательность объектов (responders), которые могут реагировать на эти события. Цепочка обработчиков позволяет событию быть переданным от одного объекта к другому, пока не будет найден подходящий обработчик события или пока цепочка не будет завершена.

🤔 Как это работает

1️⃣ Начало цепочки: В контексте iOS приложения, цепочка обработчиков событий начинается с объекта, который первым получает событие. Например, в случае касания экрана это может быть конкретный элемент управления UI (например, кнопка), который распознает касание.

2️⃣ Передача события: Если этот объект (responder) не обрабатывает событие, оно передается дальше по цепочке. Обычно следующим в цепочке является родительский элемент в иерархии представлений, и так далее, вплоть до корневого представления.

3️⃣ ViewController и дальше: Если событие достигает корневого представления и оно не обрабатывается, оно передается объекту ViewController этого представления. Затем ViewController может обработать событие или передать его дальше по цепочке.

4️⃣ UIApplication и AppDelegate: Если ни один из ViewControllers не обработал событие, оно может быть передано объекту приложения (UIApplication) и, в конечном счёте, его делегату (AppDelegate), где оно может быть обработано или проигнорировано.

🤔 Пример

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

🤔 Зачем это нужно

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

Responder chain — это система для передачи и обработки событий, которая обеспечивает последовательную передачу событий от одного объекта к другому в пределах иерархии приложения, пока событие не будет обработано или не достигнет конца цепочки. Это ключевой механизм для обработки пользовательского ввода и других событий в приложениях для платформ Apple.

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как в Swift определить класс, который не может быть наследован другими классами?
Anonymous Quiz
92%
final class
6%
static class
1%
closed class
2%
sealed class
📌 Что такое жизненный цикл объекта ?

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

Жизненный цикл объекта — это период с момента его создания до момента уничтожения. Управление жизненным циклом объекта важно для эффективного использования памяти и предотвращения утечек памяти, особенно в языках программирования, где управление памятью выполняется автоматически через механизм подсчёта ссылок (reference counting).

🤔 Создание объекта

1️⃣ Инициализация (Initialization): Объект создаётся в памяти. Это происходит при вызове инициализатора, который устанавливает начальное состояние всех свойств объекта. Инициализаторы могут быть определены с различными параметрами, позволяя создавать объекты с разными начальными значениями.

🤔 Использование объекта

2️⃣ Доступ и изменение состояния: После создания объекта его методы могут быть вызваны, а свойства — читаться или изменяться. Это активный период в жизненном цикле объекта, когда он выполняет полезную работу.

🤔 Уничтожение объекта

3️⃣ Деинициализация (Deinitialization): Непосредственно перед тем, как объект будет уничтожен, вызывается деинициализатор (если он определён). Это дает возможность освободить ресурсы или выполнить другие операции по очистке. Деинициализаторы не принимают никаких параметров и указываются с помощью ключевого слова deinit.

4️⃣ Освобождение памяти (Deallocation): Когда на объект больше нет активных ссылок (когда счётчик ссылок достигает нуля), память, занимаемая объектом, освобождается. Это означает, что объект удаляется из памяти, и ресурсы, которые он использовал, становятся доступными для других объектов или программ.

Управление памятью объектов осуществляется через подсчёт ссылок (ARC — Automatic Reference Counting). ARC автоматически отслеживает, сколько активных ссылок указывает на каждый объект. Когда количество ссылок на объект уменьшается до нуля, Swift понимает, что объект больше не нужен, и автоматически уничтожает его, освобождая занимаемую память.

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Какой тип в Swift используется для обработки текста?
Anonymous Quiz
96%
String
3%
Text
0%
Str
1%
Char
📌 В чём отличие Асинхронности от многопоточности?

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

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

Асинхронность

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

Основные характеристики асинхронности:

1️⃣ Не блокирует основной поток: Когда вы вызываете асинхронную функцию, основной поток продолжает выполнение других задач.

2️⃣ Использование замыканий или обратных вызовов: Асинхронные функции обычно принимают замыкания (closures) или используют обратные вызовы (callbacks) для выполнения кода после завершения асинхронной задачи.

3️⃣ Обещания и Future: Часто в асинхронном программировании используются такие конструкции как Promises или Future для обработки результатов асинхронных операций.

Пример на Swift с использованием async/await:
func fetchData() async -> String {
// Длительная операция
return "Данные получены"
}

func processData() {
Task {
let data = await fetchData()
print(data)
}
}

processData()


Здесь fetchData выполняется асинхронно, и основной поток не блокируется.

Многопоточность

Многопоточность (multithreading) позволяет программе выполнять несколько потоков (threads) одновременно. Каждый поток может выполнять свою задачу параллельно с другими потоками.

Основные характеристики многопоточности:

1️⃣ Параллельное выполнение: Потоки могут выполнять задачи одновременно, что позволяет полностью использовать многопроцессорные системы.

2️⃣ Сложность управления: Многопоточность сложнее в управлении из-за необходимости синхронизации данных между потоками, чтобы избежать состояния гонки (race conditions) и других проблем.

3️⃣ Пул потоков: В iOS можно использовать такие средства, как Grand Central Dispatch (GCD) и Operation Queues для управления потоками.

Пример на Swift с использованием GCD:
DispatchQueue.global(qos: .background).async {
// Длительная операция
let data = "Данные получены"

DispatchQueue.main.async {
// Обновление UI на главном потоке
print(data)
}
}


Здесь длительная операция выполняется в фоновом потоке, а результат обновляет UI на главном потоке.

🤔 Заключение

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

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Какой метод позволяет выполнить код асинхронно на главной очереди в Swift?
Anonymous Quiz
92%
DispatchQueue.main.async {}
3%
Async.runOnMain {}
📌 Что такое Swift UI и какие его преимущества?

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

SwiftUI — это фреймворк от Apple для создания пользовательских интерфейсов для всех платформ Apple, включая iOS, macOS, watchOS и tvOS. SwiftUI был представлен на WWDC 2019 и является современным и декларативным способом создания UI.

Основные преимущества SwiftUI

1️⃣ Декларативный подход:

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

   struct ContentView: View {
var body: some View {
Text("Hello, World!")
.padding()
}
}


2️⃣ Интерактивные превью в Xcode:

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

   struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}


3️⃣ Унифицированный фреймворк для всех платформ:

SwiftUI позволяет использовать один и тот же код для создания интерфейсов на всех платформах Apple. Это упрощает поддержку и развитие приложений.

   struct ContentView: View {
var body: some View {
VStack {
Text("Welcome to SwiftUI")
Button(action: {
print("Button tapped")
}) {
Text("Tap me")
}
}
}
}


4️⃣ Удобная работа с состояниями и данными:

SwiftUI предоставляет простые и мощные механизмы для управления состоянием и данными. Например, с помощью @State можно легко обновлять интерфейс при изменении данных.

   struct ContentView: View {
@State private var counter = 0

var body: some View {
VStack {
Text("Counter: \(counter)")
Button(action: {
counter += 1
}) {
Text("Increment")
}
}
}
}


5️⃣ Простая интеграция с UIKit и AppKit:

SwiftUI можно легко интегрировать с существующими проектами, написанными на UIKit или AppKit. Это позволяет постепенно мигрировать на SwiftUI, не переписывая все приложение сразу.

   struct UIKitButtonView: UIViewRepresentable {
func makeUIView(context: Context) -> UIButton {
let button = UIButton(type: .system)
button.setTitle("Press me", for: .normal)
return button
}

func updateUIView(_ uiView: UIButton, context: Context) {}
}


🤔 Заключение

SwiftUI — это мощный инструмент для создания интерфейсов, который предлагает декларативный подход, унифицированный фреймворк для всех платформ Apple, интерактивные превью, удобную работу с состояниями и простую интеграцию с существующими фреймворками.

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как в Swift создать словарь с типом ключей String и значений Int?
Anonymous Quiz
6%
{String: Int}
28%
Dictionary<String, Int>()
6%
[String, Int]()
61%
[String: Int]()
📌 Назови плюсы вайпера?

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

VIPER (View, Interactor, Presenter, Entity, Router) — это архитектурный паттерн, используемый в разработке приложений для iOS, который помогает разделить ответственность и улучшить читаемость и тестируемость кода. Рассмотрим основные преимущества использования VIPER.

Преимущества VIPER

1️⃣ Четкое разделение ответственности:

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

View: Отвечает за отображение данных и пользовательский интерфейс.

Interactor: Содержит бизнес-логику и выполняет запросы данных.

Presenter: Связывает View и Interactor, обрабатывает события и подготавливает данные для View.

Entity: Модели данных, используемые Interactor.

Router: Управляет навигацией и переходами между экранами.

2️⃣ Улучшенная тестируемость:

Четкое разделение компонентов упрощает написание модульных тестов для каждого слоя. Например, бизнес-логику можно протестировать, не затрагивая пользовательский интерфейс.
   class MockInteractor: InteractorInputProtocol {
var isFetchDataCalled = false

func fetchData() {
isFetchDataCalled = true
}
}


3️⃣ Поддерживаемость и масштабируемость:

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

4️⃣ Параллельная разработка:

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

5️⃣ Повторное использование кода:

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

6️⃣ Прозрачная навигация:

Router отвечает за навигацию и позволяет легко управлять переходами между экранами. Это упрощает поддержку маршрутов и улучшает читаемость кода, связанного с навигацией.
   class Router: RouterProtocol {
func navigateToNextScreen(from view: ViewProtocol) {
let nextViewController = NextViewController()
if let sourceView = view as? UIViewController {
sourceView.navigationController?.pushViewController(nextViewController, animated: true)
}
}
}


🤔 Заключение

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

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой оператор используется для объединения двух условий в логическое И в Swift?
Anonymous Quiz
1%
`and`
81%
`&&`
4%
`||`
14%
`&`
📌 Как синхронизировать данные между потоками(Как синхронизировать контекст)?

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

Синхронизация данных между потоками в многопоточном программировании необходима для предотвращения конфликтов, состояния гонки (race conditions) и обеспечения корректной работы приложения. В Swift и iOS для синхронизации контекста и управления доступом к данным между потоками можно использовать различные механизмы.

Основные методы синхронизации в Swift

1️⃣ Dispatch Queues (GCD)

Serial Dispatch Queues: Очереди последовательного выполнения, где задачи выполняются одна за другой, что исключает одновременное выполнение задач.

Barrier: Специальная задача, которая блокирует очередь и позволяет безопасно изменять данные, после чего остальные задачи продолжают выполнение.
   let serialQueue = DispatchQueue(label: "com.example.serialQueue")

serialQueue.async {
// Доступ к общему ресурсу
}

🤔 Пример использования барьера:
   let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)

concurrentQueue.async(flags: .barrier) {
// Безопасное изменение общего ресурса
}


2️⃣ NSLock

Класс NSLock предоставляет простой механизм блокировки для управления доступом к ресурсу между потоками.
   let lock = NSLock()

lock.lock()
// Доступ к общему ресурсу
lock.unlock()


3️⃣ Synchronized Property Wrapper

Обёртка свойств для автоматического управления доступом к общим данным.
   @propertyWrapper
struct Synchronized<T> {
private var value: T
private let lock = NSLock()

init(wrappedValue: T) {
self.value = wrappedValue
}

var wrappedValue: T {
get {
lock.lock()
defer { lock.unlock() }
return value
}
set {
lock.lock()
value = newValue
lock.unlock()
}
}
}

struct Example {
@Synchronized var sharedResource: Int = 0
}


4️⃣ OperationQueue

Класс OperationQueue позволяет управлять очередями операций и их зависимостями. Это более высокий уровень абстракции, чем GCD.
   let operationQueue = OperationQueue()

let operation = BlockOperation {
// Доступ к общему ресурсу
}

operationQueue.addOperation(operation)


5️⃣ Reader-Writer Lock

Позволяет нескольким потокам читать данные одновременно, но ограничивает запись только одним потоком.
   class ReadWriteLock {
private var lock = pthread_rwlock_t()

init() {
pthread_rwlock_init(&lock, nil)
}

func readLock() {
pthread_rwlock_rdlock(&lock)
}

func writeLock() {
pthread_rwlock_wrlock(&lock)
}

func unlock() {
pthread_rwlock_unlock(&lock)
}

deinit {
pthread_rwlock_destroy(&lock)
}
}

let rwLock = ReadWriteLock()

rwLock.readLock()
// Доступ к ресурсу для чтения
rwLock.unlock()

rwLock.writeLock()
// Доступ к ресурсу для записи
rwLock.unlock()


🤔 Заключение

Для синхронизации данных между потоками в Swift можно использовать различные методы, такие как последовательные очереди (Serial Dispatch Queues), барьеры, NSLock, обёртки свойств для синхронизации, OperationQueue и блокировки для чтения и записи (Reader-Writer Lock). Выбор подходящего метода зависит от конкретных требований приложения и сложности задачи.

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Какое ключевое слово используется для определения перечисления в Swift?
Anonymous Quiz
3%
enumerator
1%
Enumerable
96%
enum
0%
EnumType