Swift | Вопросы собесов
2.23K subscribers
30 photos
964 links
Download Telegram
🤔 Что такое вывод типов (type inference)?

Type inference — это механизм, позволяющий не указывать явно тип переменной, если компилятор может его вывести из контекста.
Например, если ты присваиваешь 42, компилятор поймёт, что это Int. Это делает код короче и чище, особенно при работе с generics и замыканиями.


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

Обеспечение безопасности работы с историей изображений в iOS-приложениях может включать несколько уровней защиты:

🟠Контроль доступа к изображениям
- Используйте Privacy Settings (NSPhotoLibraryUsageDescription, NSCameraUsageDescription) для контроля доступа к фотоальбому.
- Для ограниченного доступа в iOS 14+ используйте PHPickerViewController.
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
if status == .authorized {
// Доступ есть
} else {
// Запросить разрешение
PHPhotoLibrary.requestAuthorization { newStatus in
if newStatus == .authorized {
print("Доступ получен")
}
}
}


🟠Шифрование изображений
- Если изображения сохраняются локально, используйте AES-шифрование.
- Можно хранить ключ в Keychain или использовать Secure Enclave.
import CommonCrypto

func encryptImage(data: Data, key: Data) -> Data? {
var buffer = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0

let status = CCCrypt(
CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding), key.bytes, key.count,
nil, data.bytes, data.count, &buffer, buffer.count, &numBytesEncrypted
)

return status == kCCSuccess ? buffer.prefix(numBytesEncrypted) : nil
}


🟠Безопасное хранение изображений
Core Data с Encrypted Store – можно использовать зашифрованные базы данных, такие как SQLCipher.
FileManager + Data Protection – файлы можно хранить в Application Support с флагом .completeFileProtection.
Keychain – если нужно хранить ссылки на изображения или ключи.
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("secure_image.jpg")
try? imageData.write(to: fileURL, options: .completeFileProtection)


🟠Ограничение кеширования изображений
- Если изображение чувствительное, отключите кеширование в URLSession:
let config = URLSessionConfiguration.default
config.urlCache = nil // Отключаем кеш
let session = URLSession(configuration: config)


🟠Защита от утечек в памяти
- Убедитесь, что ссылки на изображения не создают retain cycle.
- Используйте weak ссылки в кэше изображений.
class ImageCache {
private let cache = NSCache<NSString, UIImage>()

func store(image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}

func retrieve(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
}


🟠Безопасная загрузка изображений (защита от MITM)
- Используйте HTTPS вместо HTTP.
- Включите App Transport Security (ATS) в Info.plist.
- Верифицируйте SSL-сертификаты при загрузке.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if let serverTrust = challenge.protectionSpace.serverTrust {
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Где сохраняется выбор темы пользователем (светлая/тёмная)?

Чаще всего тема сохраняется в UserDefaults (iOS), SharedPreferences (Android) или базе данных, если нужно синхронизировать с сервером. Это позволяет восстановить выбор при следующем запуске приложения.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Может ли у UI View не быть layer'а и наоборот?

UIView всегда имеет CALayer, так как UIView — это обёртка над CALayer в UIKit.
CALayer может существовать без UIView, потому что это низкоуровневый элемент Core Animation, который не зависит от UIKit.

🚩`UIView` всегда содержит `CALayer`

Каждый UIView внутри себя содержит CALayer, который отвечает за отрисовку.
let view = UIView()
print(view.layer) // Всегда существует!


🚩`CALayer` может существовать без `UIView`

CALayer можно создать и добавить в иерархию без UIView.
let layer = CALayer()
layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor

if let window = UIApplication.shared.windows.first {
window.layer.addSublayer(layer) // Добавляем без UIView!
}


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

Барьер (barrier) — это механизм синхронизации в многопоточности. Он блокирует доступ к ресурсу, пока не завершится текущая операция, обеспечивая безопасную запись при параллельном чтении (например, в DispatchQueue с .barrier).


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

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

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

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

p2.x = 10

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


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


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

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

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

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


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

arr2.append(4)

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


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

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

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

Можно реализовать кэш:
- Через обычный словарь или мапу (ключ — запрос, значение — ответ).
- Устанавливать ограничение по времени жизни (например, TTL) и вручную очищать старые значения.
- Добавлять механизм проверки валидности (по дате, флагу, внешнему событию).
- Использовать структуры с ограничением размера, удаляя наименее используемые элементы (например, LRU).


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

Барьер (Barrier) – это механизм синхронизации потоков, который позволяет контролировать порядок выполнения операций** в многопоточной среде.

🚩Барьеры памяти (Memory Barriers)

Используются в многопоточном программировании для управления порядком операций с памятью.
В многопоточной среде процессоры и компиляторы могут оптимизировать порядок команд, что может привести к непредсказуемому поведению. Барьеры памяти предотвращают это.
#include <stdatomic.h>

atomic_int sharedValue = 0;

void updateValue() {
atomic_store_explicit(&sharedValue, 10, memory_order_release);
}

void readValue() {
int value = atomic_load_explicit(&sharedValue, memory_order_acquire);
}


🚩Барьеры в GCD (`dispatch_barrier`)

Используются в Grand Central Dispatch (GCD)** для контроля порядка выполнения задач в DispatchQueue.
- Позволяет блокировать очередь на время выполнения задачи.
- Все задачи до барьера выполняются параллельно.
- Барьер ждёт завершения всех предыдущих задач, выполняется эксклюзивно, затем разрешает следующие задачи.
let queue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)

queue.async {
print("Задача 1")
}
queue.async {
print("Задача 2")
}

// БАРЬЕРНАЯ ОПЕРАЦИЯ
queue.async(flags: .barrier) {
print("🔴 Барьер: все предыдущие задачи завершены, выполняюсь один!")
}

queue.async {
print("Задача 3")
}


🚩Барьеры в OpenMP (Параллельные вычисления)

В OpenMP (#pragma omp barrier) ждёт завершения всех потоков перед выполнением следующего кода.
#pragma omp parallel
{
printf("До барьера\n");
#pragma omp barrier
printf("После барьера\n");
}


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

Для value-типов очистка памяти происходит при выходе за область видимости. Для ссылочных — важно отслеживать retain cycles и использовать weak/unowned. Можно реализовать протокол CacheClearable с методом очистки, а ключи кэшировать в словарях с NSCache, который автоматически очищает содержимое при нехватке памяти.


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

Подписку на уведомления (NotificationCenter), KVO или Combine в жизненном цикле UIViewController лучше размещать в методах, где гарантируется её актуальность и корректное удаление.

🟠Подписка в `viewDidLoad()`
Подписка на события обычно происходит в `viewDidLoad()`, так как этот метод вызывается один раз при создании контроллера.
override func viewDidLoad() {
super.viewDidLoad()

NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification),
name: .someNotification,
object: nil
)
}

@objc func handleNotification(_ notification: Notification) {
print("Получено уведомление")
}


🟠Подписка в `viewWillAppear()` – если уведомления нужны только при отображении экрана
Если подписка должна работать только когда экран на экране, используем viewWillAppear().
var cancellable: AnyCancellable?

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

cancellable = NotificationCenter.default.publisher(for: .someNotification)
.sink { _ in
print("Событие получено")
}
}


🟠`viewWillDisappear()` – отписка от событий
Когда контроллер скрывается, подписки можно удалить, чтобы избежать ненужных вызовов.
Удаление подписки на NotificationCenter:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

NotificationCenter.default.removeObserver(self, name: .someNotification, object: nil)
}


Удаление Combine подписки (cancellable)
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

cancellable?.cancel()
cancellable = nil
}


🟠`deinit` – отписка, если подписка создаётся в `viewDidLoad()`
Если подписка работает на протяжении всего жизненного цикла контроллера, её можно удалить в `deinit`.
deinit {
NotificationCenter.default.removeObserver(self)
}


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

Коллекции Swift:
- Типизированные — Array<Int>, Set<String>, Dictionary<String, Int>.
- Итерабельные, поддерживают for-in, map, filter, reduce.
- Безопасные по индексу — доступ за границами вызывает crash.
- Имеют value semantics — при копировании создаются независимые копии (если не оптимизировано через COW).
Swift также предоставляет lazy, stride, enumerated, zip, prefix, что делает работу с коллекциями очень выразительной и безопасной.


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

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

🚩UIView

UIView — это базовый класс для всех элементов пользовательского интерфейса в iOS. Он представляет собой прямоугольную область на экране, которая может отображать контент и реагировать на события пользователя, такие как нажатия, жесты и касания.
UIView предоставляет множество свойств и методов для управления внешним видом, положением и поведением представления. Примеры включают frame, bounds, center, backgroundColor, alpha, isHidden, и subviews. UIView также поддерживает анимации, автолэйаут и работу с событийной системой.
UIView обрабатывает пользовательские события, такие как касания и жесты. Он предоставляет методы, такие как touchesBegan, touchesMoved, и touchesEnded, для обработки этих событий.
   let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myView.backgroundColor = .blue
view.addSubview(myView)


🚩CALayer

CALayer — это базовый класс для всех графических слоев, используемых в Core Animation. Он обеспечивает низкоуровневую поддержку для рендеринга, анимации и композиции графики.
CALayer предоставляет свойства для управления внешним видом, такими как backgroundColor, borderWidth, cornerRadius, shadowOpacity, contents (для отображения изображений), и transform. CALayer также поддерживает анимации, используя ключевые кадры и основные анимации. 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

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

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

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

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В каком случае у Bounce может изменяться значение origin?

При активации bounce-эффекта (перетягивания) в UIScrollView, когда пользователь тянет содержимое за границы:
- Меняется bounds.origin — она уходит за пределы contentOffset.
- Это происходит во время резкого скролла, обновлений или pull-to-refresh.
После отпускания — origin возвращается в нормальные границы с анимацией.


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

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

🚩Ключи

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

🚩Значения

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


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

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

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


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

Отделённый слайс массива в большинстве языков (например, в Python, Swift) будет того же типа, что и оригинальный массив. Однако в зависимости от языка — это может быть новая копия или представление (view) на те же данные.


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

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

🚩Что такое Future?

Future (или Promise в некоторых реализациях) — это объект, который представляет значение, которое станет доступным в будущем после завершения асинхронной операции. Это удобно, когда нужно работать с кодом, который выполняется не мгновенно
Запросы в сеть (API)
Чтение файлов
Долгие вычисления
В Swift Future чаще всего используется в рамках Combine.

🚩Как работает Future в Swift (на примере Combine)?

В Combine есть структура Future, которая позволяет создать асинхронную операцию и подписаться на ее результат:
import Combine

// Функция, которая возвращает Future
func fetchData() -> Future<String, Error> {
return Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
let success = Bool.random() // Симулируем успех или ошибку

if success {
promise(.success("Данные загружены!"))
} else {
promise(.failure(NSError(domain: "Ошибка загрузки", code: -1, userInfo: nil)))
}
}
}
}

// Используем Future
let future = fetchData()

let cancellable = future.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Завершено без ошибок")
case .failure(let error):
print("Ошибка: \(error.localizedDescription)")
}
}, receiveValue: { value in
print("Получены данные: \(value)")
})


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

Когда нужна одноразовая асинхронная операция (например, запрос в сеть)
Когда используешь Combine и хочешь обернуть асинхронный код в реактивный стиль
Если в будущем планируешь объединять несколько асинхронных операций (композиция Future)

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как сделать класс наблюдаемым (начиная с iOS 17)?

С iOS 17 используется
@Observable — новая система реактивности.
Чтобы сделать класс наблюдаемым, достаточно:
- Отметить его как
@Observable.
- Использовать обычные свойства, без
@Published.
- SwiftUI будет автоматически отслеживать изменения и обновлять интерфейс.
Это заменяет необходимость в
@ObservedObject, @StateObject, @Published в большинстве случаев.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие плюсы и минусы layout'а?

Каждый способ создания макетов (layout'а) в iOS-разработке имеет свои преимущества и недостатки.

🚩Interface Builder (IB)

Визуальное редактирование
Удобный графический интерфейс для быстрой настройки и визуального просмотра изменений.
Интеграция с Auto Layout
Простая настройка ограничений (constraints) для адаптивного интерфейса.
Быстрое прототипирование
Возможность быстрого создания и изменения макетов без написания кода.
Меньшая гибкость
Ограниченные возможности для создания сложных и динамических макетов.
Конфликты при совместной работе
Трудности при слиянии изменений в storyboard или xib файлах в больших командах.
Производительность
Более медленное время загрузки по сравнению с программными подходами.

🚩Auto Layout

Адаптивность
Поддержка различных устройств и ориентаций экрана.
Мощные инструменты
Возможность создания сложных и адаптивных макетов с помощью ограничений.
Интеграция с Interface Builder
Упрощенная настройка ограничений через визуальный интерфейс.
Крутая кривая обучения
Может быть сложно освоить, особенно для новичков.
Управление сложными макетами
Требует тщательного планирования и может стать сложным при работе с большим количеством ограничений.

🚩Programmatic Layout

Полный контроль
Возможность точной настройки макета с помощью кода.
Гибкость
Легкость создания динамических и условных макетов.
Управление версиями
Легче управлять изменениями в коде по сравнению с визуальными файлами.
Большая трудоемкость
Требует больше времени и усилий для настройки, особенно для сложных макетов.
Меньшая наглядность
Отсутствие визуального редактора может затруднить представление конечного результата.

🚩Stack Views

Упрощение макетов
Легкость создания и управления сложными макетами с минимальными усилиями.
Интеграция с Auto Layout
Автоматическое управление ограничениями для вложенных элементов.
Адаптивность
Поддержка различных ориентаций и размеров экранов.
Ограниченная гибкость
Менее гибкие по сравнению с чистым Auto Layout или программными подходами.
Поддержка
Не всегда подходят для всех типов макетов, особенно для более сложных компоновок.

🚩SwiftUI

Декларативный синтаксис
Простота и понятность кода благодаря декларативному подходу.
Превью в реальном времени
Мгновенное обновление интерфейса при изменении кода.
Интеграция с Swift
Современные возможности языка и тесная интеграция с экосистемой Apple.
Кроссплатформенность
Поддержка различных платформ (iOS, macOS, watchOS, tvOS).
Требования к версии iOS
Поддержка только iOS 13 и выше, что может ограничить использование на старых устройствах.
Зрелость фреймворка
Некоторые функции еще находятся в стадии разработки, и могут быть ограничены возможности по сравнению с UIKit.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 RunLoop общий для очередей или на каждую очередь свой?

RunLoop работает только на потоках, где он был явно создан. У каждой main queue и кастомного потока может быть свой RunLoop. Фоновым очередям в GCD RunLoop не нужен по умолчанию, пока не используется таймер или input source.


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

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

🚩Почему нет множественного наследования классов?

Swift запрещает множественное наследование классов, потому что оно может привести к конфликтам и алмазной проблеме (diamond problem).
Допустим, в языке с поддержкой множественного наследования у нас есть два родительских класса с одинаковым методом:
class A {
public:
void greet() { cout << "Hello from A"; }
};

class B {
public:
void greet() { cout << "Hello from B"; }
};

// C наследуется от A и B
class C : public A, public B {};

C obj;
obj.greet(); // Какой метод вызвать? A или B?


🚩Как обойти ограничение? Используем протоколы!

В Swift можно реализовать множественное наследование через протоколы, поскольку класс может соответствовать нескольким протоколам одновременно.
protocol Flyable {
func fly()
}

protocol Swimmable {
func swim()
}

class Animal {}

class Duck: Animal, Flyable, Swimmable {
func fly() {
print("Утка летит")
}

func swim() {
print("Утка плывёт")
}
}

let duck = Duck()
duck.fly() // Утка летит
duck.swim() // Утка плывёт


🚩Что делать, если нужен код по умолчанию?

Если хочется, чтобы протокол предоставлял реализацию по умолчанию (почти как родительский класс), можно использовать extension:
protocol Walker {
func walk()
}

extension Walker {
func walk() {
print("Иду вперёд")
}
}

class Person: Walker {}

let human = Person()
human.walk() // "Иду вперёд" (метод взят из extension)


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