Swift | Вопросы собесов
2.13K subscribers
28 photos
947 links
Download Telegram
🤔 В какой момент вызывается метод 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
🤔 Можно ли наследовать структуру от нескольких родителей?

В Swift структуры не поддерживают множественное наследование, так как наследование вообще не применяется к структурам. Наследование — это механизм, доступный только для классов. Структуры и перечисления (enums) в Swift могут принимать протоколы, что позволяет им реализовывать множественное поведение, но не наследовать реализацию.

🚩Альтернативы наследованию для структур

🟠Протоколы (Protocols):
Протоколы в Swift позволяют описывать интерфейсы и требования, которые должны выполнять структуры, классы или перечисления. Это основной способ добиться множественного поведения.
protocol Describable {
var description: String { get }
}

protocol Identifiable {
var id: Int { get }
}

struct User: Describable, Identifiable {
var description: String
var id: Int
}


🟠Композиция (Composition):
Композиция предполагает создание сложных типов путем комбинирования более простых типов. Это позволяет гибко создавать функциональные структуры без необходимости наследования.
struct Address {
var street: String
var city: String
}

struct Person {
var name: String
var address: Address
}

let address = Address(street: "123 Main St", city: "New York")
let person = Person(name: "John", address: address)


🟠Расширения (Extensions):
Расширения позволяют добавлять методы, свойства и функциональность к существующим типам без необходимости изменять исходный код этих типов.
protocol Greetable {
func greet()
}

extension Greetable {
func greet() {
print("Hello!")
}
}

struct User: Greetable {
var name: String
}

let user = User(name: "Alice")
user.greet() // Output: Hello!


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
🤔 Какой протокол в Swift используется для создания объектов, поддерживающих копирование?
Anonymous Quiz
14%
Clonable
34%
Copying
47%
NSCopying
6%
CopyProtocol
1
🤔 Что такое деинициализатор?

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

🚩Основные характеристики деинициализаторов

🟠Определение и синтаксис:
Деинициализаторы объявляются с помощью ключевого слова deinit. Классы могут иметь только один деинициализатор. Деинициализаторы не принимают аргументов и не возвращают значений.

🟠Когда вызывается:
Деинициализатор вызывается автоматически системой управления памятью Swift (ARC) перед тем, как объект класса будет освобожден из памяти. Этот метод не может быть вызван явно.

🟠Использование:
Деинициализаторы используются для выполнения завершающих операций, таких как освобождение ресурсов, закрытие файлов, остановка таймеров и отмена сетевых запросов.
class Resource {
init() {
print("Resource initialized")
}

deinit {
print("Resource deinitialized")
}
}

var resource: Resource? = Resource() // Output: "Resource initialized"
resource = nil // Output: "Resource deinitialized"


В этом примере:
Класс Resource имеет деинициализатор, который выводит сообщение при освобождении объекта. Переменная resource сначала инициализируется экземпляром Resource, что приводит к вызову инициализатора. Когда переменной resource присваивается nil, объект освобождается, и вызывается деинициализатор.

🚩Применение деинициализаторов

🟠Освобождение ресурсов:
Деинициализаторы часто используются для освобождения ресурсов, таких как файлы или сетевые соединения.
class FileHandler {
let file: File

init(file: File) {
self.file = file
// Открытие файла
}

deinit {
// Закрытие файла
print("Файл закрыт")
}
}


🟠Остановка таймеров:
Если класс использует таймер, деинициализатор может быть использован для его остановки.
class TimerClass {
var timer: Timer?

init() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
print("Таймер работает")
}
}

deinit {
timer?.invalidate()
print("Таймер остановлен")
}
}


🟠Отмена сетевых запросов:
Если класс выполняет сетевые запросы, деинициализатор может быть использован для их отмены.
class NetworkManager {
var dataTask: URLSessionDataTask?

func fetchData() {
let url = URL(string: "https://example.com")!
dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
// Обработка ответа
}
dataTask?.resume()
}

deinit {
dataTask?.cancel()
print("Сетевой запрос отменён")
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Какой протокол используется для создания пользовательских операторов в Swift?
Anonymous Quiz
39%
OperatorProtocol
33%
CustomOperator
19%
ExpressibleByOperator
9%
ExpressibleByIntegerLiteral
👾3🤔1
🤔 Что такое ритейн релиз?

Ретейн-релиз (retain-release) — это модель управления памятью, которая использовалась в Objective-C до появления автоматического подсчета ссылок (Automatic Reference Counting, ARC). В этой модели разработчик вручную контролирует время жизни объектов, используя методы retain, release и autorelease. В Swift эта модель заменена ARC, но понимание ретейн-релиз важно для работы с устаревшим кодом и интеграции с Objective-C.

🚩Основные концепции ретейн-релиз

🟠Счётчик ссылок (Reference Count):
Каждый объект в памяти имеет счётчик ссылок, который отслеживает количество сильных ссылок на этот объект. Когда создается новая сильная ссылка на объект, счётчик ссылок увеличивается. Когда сильная ссылка удаляется, счётчик ссылок уменьшается.

🟠Методы управления памятью:
retain: Увеличивает счётчик ссылок на объект.
release: Уменьшает счётчик ссылок на объект. Когда счётчик достигает нуля, объект освобождается из памяти.
autorelease: Помещает объект в autorelease pool, который отправляет сообщение release объектам при спуске (drain) пула.

Autorelease Pool
Это механизм для управления временными объектами, который автоматически освобождает их память после завершения текущего цикла событий. Autorelease pool используется для временного хранения объектов, которым нужно отправить сообщение release позже.

@autoreleasepool {
NSString *tempString = [[NSString alloc] initWithFormat:@"Hello, %@", @"World"];
[tempString autorelease];
// tempString будет автоматически освобождена в конце блока autoreleasepool
}


🟠ARC (Automatic Reference Counting)
В Swift управление памятью автоматизировано с помощью ARC, который выполняет те же действия, что и ретейн-релиз, но автоматически. Разработчик больше не должен явно вызывать retain и release, это делает компилятор.
class MyClass {
var value: Int

init(value: Int) {
self.value = value
print("Object initialized")
}

deinit {
print("Object deinitialized")
}
}

var obj: MyClass? = MyClass(value: 10) // Счётчик ссылок: 1
obj = nil // Счётчик ссылок: 0, объект освобождается из памяти


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🤔 Какое ключевое слово используется для предотвращения наследования класса в Swift?
Anonymous Quiz
3%
sealed
90%
final
4%
static
4%
private
1