Swift | Вопросы собесов
2.13K subscribers
28 photos
947 links
Download Telegram
📌 Когда value типы могут стать reference?

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

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

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)
Когда value тип заворачивается в объект класса, он хранится в куче.

🤔 Пример:
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️⃣ Свойства классов

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

🤔 Пример:
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️⃣ Коллекции, содержащие value типы

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

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

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


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

🤔 Заключение

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

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥3👍1
🤔 Какой протокол необходимо использовать для реализации асинхронных последовательностей в Swift?
Anonymous Quiz
5%
Codable
18%
Sequence
73%
AsyncSequence
4%
IteratorProtocol
👍2
📌 Что такое UIResponder?

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

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

🤔 Основные особенности

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

Объекты, унаследованные от UIResponder, могут обрабатывать различные события через методы, такие как touchesBegan, touchesMoved, touchesEnded и touchesCancelled.

2️⃣ Цепочка ответчиков:

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

🤔 Классы-наследники

UIView: Обрабатывает пользовательский интерфейс и взаимодействие.

UIViewController: Управляет экраном или его частью.

UIApplication: Управляет жизненным циклом приложения.

UIWindow: Контейнер для представлений и контроллеров.

🤔 Пример использования
class CustomView: UIView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
print("Touches began")
}
}


🤔 Заключение

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

В двух фразах: UIResponder обрабатывает события в iOS и управляет цепочкой ответчиков. Он является базовым классом для таких объектов, как UIView и UIViewController, обеспечивая их способность реагировать на события.

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍4
🤔 Как называется механизм в Swift, позволяющий передавать функции в качестве параметров или возвращать их в качестве результата?
Anonymous Quiz
92%
Замыкания
3%
Протоколы
4%
Делегаты
1%
Модули
1
🤔 Что такое Autorelease pool?

Autorelease pool — это механизм управления памятью в Objective-C и Swift, который помогает автоматизировать освобождение объектов, когда они больше не нужны. Этот механизм используется для временного хранения объектов, которым необходимо отправить сообщение release в будущем, чтобы освободить их память. Autorelease pool обеспечивает автоматическое управление памятью и предотвращает утечки памяти, особенно в случаях, когда создаётся много временных объектов.

🚩Основные аспекты Autorelease pool

🟠Работа с временными объектами: Когда вы создаёте объект, который отправляется в autorelease pool, он не освобождается сразу, а помещается в пул. Когда пул "спускается" (drains), всем объектам в пуле отправляется сообщение release.
🟠Создание и использование Autorelease pool: В Swift и Objective-C вы можете создать собственные autorelease pools для управления памятью в циклах или других местах, где создаётся много временных объектов.

Objective-C:
@autoreleasepool {
// Создание временных объектов
NSString *tempString = [[NSString alloc] initWithFormat:@"Hello, %@", @"World"];
// tempString автоматически освободится, когда пул спустится
}


Swift:
autoreleasepool {
// Создание временных объектов
let tempString = NSString(format: "Hello, %@", "World")
// tempString автоматически освободится, когда пул спустится
}


🚩Зачем нужен Autorelease pool

Управление памятью в циклах: При создании большого количества временных объектов внутри цикла autorelease pool предотвращает увеличение использования памяти.
   for i in 0..<1000 {
autoreleasepool {
let tempString = NSString(format: "Iteration %d", i)
// tempString освобождается в конце каждой итерации
}
}


Автоматическое освобождение объектов: Autorelease pool позволяет избежать явного вызова release для каждого объекта, предоставляя автоматическое управление памятью.

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

Создание объектов: Когда объект создаётся с использованием методов, которые возвращают autoreleased объект, он добавляется в текущий autorelease pool.
   NSString *string = [NSString stringWithFormat:@"Hello, World"];


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

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

Метод viewWillAppear вызывается в жизненном цикле UIViewController перед тем, как его представление (view) становится видимым пользователю. Этот метод вызывается каждый раз, когда представление контроллера собирается появиться на экране, даже если оно уже было загружено в память.

🚩Жизненный цикл UIViewController

Загрузка представления:
🟠loadView(): Вызывается, когда представление контроллера загружается в память.
🟠viewDidLoad(): Вызывается после загрузки представления в память. Используется для первоначальной настройки представления и инициализации данных.

Перед появлением на экране: viewWillAppear(_:): Вызывается непосредственно перед тем, как представление контроллера становится видимым на экране. Это хороший момент для обновления данных и интерфейса, если они могли измениться.

Появление на экране: viewDidAppear(_:): Вызывается после того, как представление контроллера стало видимым на экране. Здесь можно запускать анимации или начинать задачи, которые должны выполняться только после того, как представление полностью отображено.

Перед исчезновением с экрана: viewWillDisappear(_:): Вызывается непосредственно перед тем, как представление контроллера исчезнет с экрана. Это подходящее место для остановки анимаций, сохранения состояния и освобождения ресурсов.

Исчезновение с экрана: viewDidDisappear(_:): Вызывается после того, как представление контроллера исчезло с экрана. Используется для выполнения действий, которые должны произойти после того, как представление перестало быть видимым.

class MyViewController: UIViewController {

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

// Обновление интерфейса перед тем, как представление станет видимым
print("viewWillAppear: Представление скоро станет видимым")

// Обновление данных
updateData()
}

func updateData() {
// Логика обновления данных
}
}


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

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
6
🤔 Какое ключевое слово используется для объявления свойств с ленивой инициализацией в Swift?
Anonymous Quiz
6%
weak
94%
lazy
0%
unowned
0%
deferred
1
🤔 Расскажи про memory managment в ios?

Управление памятью (Memory Management) в iOS включает использование автоматического подсчета ссылок (ARC) и инструментов Xcode для анализа и профилирования памяти. ARC автоматически управляет памятью, увеличивая и уменьшая счетчик ссылок на объекты. Когда объект больше не имеет сильных ссылок (strong references), он освобождается.

🚩Основные механизмы управления памятью

Automatic Reference Counting (ARC)
🟠Сильные ссылки (Strong References) удерживают объект в памяти.
🟠Лабые ссылки (Weak References) не удерживают объект в памяти и автоматически обнуляются при освобождении объекта.
🟠Неустранимые ссылки (Unowned References) предполагают, что объект всегда будет существовать до тех пор, пока существует неустранимая ссылка.
class Person {
var name: String
weak var spouse: Person?
init(name: String) {
self.name = name
}
}


🚩Инструменты для управления памятью

Xcode Instruments
🟠Leaks: Обнаружение утечек памяти.
🟠Allocations: Отслеживание распределения и использования

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Какой протокол необходимо реализовать для поддержки сопоставления шаблонов (pattern matching) в Swift?
Anonymous Quiz
41%
Equatable
39%
Comparable
12%
Hashable
7%
CaseIterable
👍1
🤔 В чем различие очередей силиал и конкарент?

Очереди (queues) в iOS и macOS используются для управления задачами в многопоточном программировании с помощью Grand Central Dispatch (GCD). Существуют два основных типа очередей: последовательные (serial) и конкурентные (concurrent). Они различаются по способу выполнения задач.

🚩Последовательные очереди (Serial Queues)

🟠Описание: Выполняют задачи одну за другой в порядке их добавления. Каждая задача начинается только после завершения предыдущей.
🟠Использование: Подходят для задач, которые должны выполняться последовательно, чтобы избежать состояния гонки (race conditions) и конфликтов доступа к ресурсам.

let serialQueue = DispatchQueue(label: "com.example.serialQueue")
serialQueue.async {
print("Task 1")
}
serialQueue.async {
print("Task 2")
}
// Task 1 будет выполнена перед Task 2


🚩Конкурентные очереди (Concurrent Queues)

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

let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
concurrentQueue.async {
print("Task 1")
}
concurrentQueue.async {
print("Task 2")
}
// Task 1 и Task 2 могут быть выполнены одновременно


🚩Главная очередь (Main Queue)

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

DispatchQueue.main.async {
print("Update UI")
}
// Эта задача будет выполнена на главном потоке


🚩Глобальные очереди (Global Queues)

🟠Описание: Конкурентные очереди, предоставляемые системой с различными уровнями приоритета (QoS).
🟠Использование: Выполнение задач с заданным приоритетом.

DispatchQueue.global(qos: .userInitiated).async {
print("High priority task")
}
DispatchQueue.global(qos: .background).async {
print("Low priority task")
}
// Задачи будут выполнены в соответствии с их приоритетом


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61
🤔 Какой оператор используется для приведения типа в Swift, при условии, что приведение может завершиться неудачно?
Anonymous Quiz
8%
as!
85%
as?
4%
as
2%
is?
👍1
🤔 Когда начинает работать динамическая диспетчеризация?

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

Динамическая диспетчеризация в Swift начинает работать, когда методы или свойства вызываются во время выполнения программы (runtime), а не на этапе компиляции. Это может быть связано с различными механизмами, включая использование @objc и динамических ключевых слов, протоколы с необязательной реализацией, и взаимодействие с Objective-C API. Давайте рассмотрим основные случаи, когда применяется динамическая диспетчеризация:

🚩Основные случаи использования динамической диспетчеризации

Использование `@objc` и динамических ключевых слов: Методы и свойства, помеченные атрибутом @objc или ключевым словом dynamic, используют динамическую диспетчеризацию через Objective-C runtime. Это позволяет изменять поведение методов в процессе выполнения, например, через механизм замен (swizzling).
import Foundation

class MyClass: NSObject {
@objc dynamic func myMethod() {
print("Original implementation")
}
}

let obj = MyClass()
obj.myMethod() // Вызов через динамическую диспетчеризацию


Протоколы с необязательной реализацией: Протоколы, объявленные с @objc, могут иметь необязательные методы, которые вызываются через динамическую диспетчеризацию. Это позволяет проверять наличие метода и вызывать его только при наличии.
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}

class MyClass: NSObject, MyProtocol {
func optionalMethod() {
print("Optional method implementation")
}
}

let obj: MyProtocol = MyClass()
obj.optionalMethod?() // Вызов через динамическую диспетчеризацию


Интерактивное взаимодействие с Objective-C API: Методы, которые взаимодействуют с Objective-C API или наследуются от классов, написанных на Objective-C, используют динамическую диспетчеризацию для вызова методов через Objective-C runtime.
import UIKit

class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Этот метод вызывается через динамическую диспетчеризацию
}
}


🚩Преимущества и недостатки динамической диспетчеризации

Преимущества:
🟠Гибкость: Позволяет изменять реализацию методов во время выполнения.
🟠Совместимость: Обеспечивает взаимодействие с Objective-C кодом и библиотеками.
🟠Необязательные методы в протоколах: Упрощает работу с протоколами, где реализация методов может быть необязательной.

Недостатки:
🟠Производительность: Динамическая диспетчеризация медленнее, чем статическая, из-за необходимости поиска метода в runtime.
🟠Сложность отладки: Усложняет отладку и понимание кода, так как методы могут изменяться во время выполнения.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
🤔 Какой модификатор доступа позволяет использовать элементы только в пределах того же модуля, но не вне его?
Anonymous Quiz
3%
open
12%
public
58%
internal
27%
private
👍2
🤔 Какие есть фрейм ворк механизмы в айос для выполненной бэкраунд задач?

В 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
👍1
🤔 Какой механизм Swift позволяет структурам, классам и перечислениям автоматом создавать копии своих экземпляров?
Anonymous Quiz
28%
Deep Copy
10%
Shallow Copy
25%
Copy Constructor
38%
Value Semantics
🤔12👾3
🤔 Что такое actor?

actor — это новый тип, введённый в Swift 5.5, который предназначен для упрощения и повышения безопасности многопоточного программирования. actor позволяет инкапсулировать состояние и обеспечивает синхронизацию доступа к этому состоянию, предотвращая состояния гонки (race conditions).

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

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

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

🟠Асинхронные вызовы
Вызов методов actor и доступ к его свойствам извне осуществляется через асинхронные функции с использованием await.

Пример использования actor
actor Counter {
private var value = 0

func increment() {
value += 1
}

func getValue() -> Int {
return value
}
}

let counter = Counter()

Task {
await counter.increment()
let value = await counter.getValue()
print("Counter value: \(value)")
}


🚩Как предотвращает состояния гонки

🟠Изоляция состояния
Внутреннее состояние actor доступно только через методы и свойства самого actor. Прямой доступ к свойствам извне невозможен.
🟠Асинхронный доступ
Все взаимодействия с actor из других контекстов требуют использования await, что обеспечивает синхронизацию доступа.

🚩Сравнение с другими механизмами синхронизации

🟠`actor` vs. GCD/Locks
Использование actor упрощает код и делает его более безопасным по сравнению с ручным использованием Grand Central Dispatch (GCD) или мьютексов для синхронизации. actor автоматически управляет синхронизацией, устраняя необходимость в ручном управлении очередями и блокировками
class Counter {
private var value = 0
private let queue = DispatchQueue(label: "com.example.counter")

func increment() {
queue.sync {
value += 1
}
}

func getValue() -> Int {
return queue.sync {
return value
}
}
}


🟠Мьютекс:
class Counter {
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
}
}


🚩Преимущества `actor`

🟠Упрощение кода: Убирает необходимость ручного управления синхронизацией, делая код более читаемым и поддерживаемым.
🟠Безопасность многопоточности: Автоматически предотвращает состояния гонки, обеспечивая безопасный доступ к данным.
🟠Интеграция с асинхронными функциями: Легко сочетается с асинхронным программированием в Swift, используя async и await.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥4
🤔 Какое ключевое слово используется для создания свойства или метода, доступного только внутри расширения?
Anonymous Quiz
17%
fileprivate
44%
private
17%
internal
21%
extension
🤔11🤯3👍1😁1
🤔 Если свою структуру создадим она скопируется или будет ждать пока что-то в ней поменяем?

В Swift структуры являются типами значений (value types), что означает, что они по умолчанию копируются при передаче или присвоении. Однако копирование структуры происходит только при изменении (copy-on-write) её состояния, чтобы оптимизировать производительность и снизить избыточные копии. Рассмотрим подробнее, как это работает.

🚩Копирование структур (Value Types) в Swift

struct MyStruct {
var value: Int
}

var a = MyStruct(value: 10)
var b = a // Копия создается, но фактически это происходит "лениво"
b.value = 20 // В этот момент происходит копирование, так как структура изменяется
print(a.value) // Output: 10
print(b.value) // Output: 20


🟠Переменная a создается и инициализируется значением 10.
🟠Переменной b присваивается значение a. На этом этапе копия не создается, так как копирование структур в Swift оптимизировано и происходит лениво.
🟠Когда изменяется значение свойства value структуры b, происходит копирование, чтобы изменить b без изменения a.

🚩Copy-on-Write

Это оптимизация, при которой фактическое копирование структуры происходит только тогда, когда необходимо изменить её содержимое. До тех пор, пока структура не изменяется, обе переменные будут ссылаться на одни и те же данные.
struct LargeStruct {
var data = [Int](repeating: 0, count: 1000)
}

var x = LargeStruct()
var y = x // Копия не создается сразу
y.data[0] = 1 // Копирование происходит здесь, при изменении
print(x.data[0]) // Output: 0
print(y.data[0]) // Output: 1


🟠Переменной x присваивается структура LargeStruct, содержащая массив данных.
🟠Переменной y присваивается значение x. На этом этапе копия не создается.
🟠Когда изменяется элемент массива data в структуре y, происходит копирование данных, чтобы x и y имели свои собственные копии массива.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Какой механизм в Swift позволяет типам адаптировать интерфейс к требованиям протокола на лету?
Anonymous Quiz
15%
Delegation
26%
Adapter
44%
Protocol Extension
16%
Type Erasure
😁4