Swift | Вопросы собесов
2.13K subscribers
28 photos
949 links
Download Telegram
🤔 Какие есть два типа инициализаторов?

Существует два типа инициализаторов: статические и нестатические.
Статические инициализаторы (`static`) выполняются один раз при загрузке класса и инициализируют статические переменные.
Нестатические инициализаторы выполняются при создании каждого экземпляра класса и используются для инициализации нестатических переменных.


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

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

🟠Композиция
Композиция включает объекты других классов как поля и делегирует им работу, что позволяет гибко изменять поведение во время выполнения.
protocol Engine {
func start()
}

class Car {
private let engine: Engine

init(engine: Engine) {
self.engine = engine
}

func start() {
engine.start()
}
}

class ElectricEngine: Engine {
func start() {
print("Electric engine starting...")
}
}

class GasolineEngine: Engine {
func start() {
print("Gasoline engine starting...")
}
}

let electricCar = Car(engine: ElectricEngine())
let gasolineCar = Car(engine: GasolineEngine())
electricCar.start()
gasolineCar.start()


🟠Протоколы и интерфейсы
Протоколы определяют набор методов и свойств, которые класс или структура должны реализовать, обеспечивая гибкость и переиспользуемость компонентов.
protocol Drawable {
func draw()
}

class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}

class Square: Drawable {
func draw() {
print("Drawing a square")
}
}

func render(drawable: Drawable) {
drawable.draw()
}

let shapes: [Drawable] = [Circle(), Square()]
shapes.forEach { render(drawable: $0) }


🟠Категории и расширения (Extensions)
Расширения добавляют новые методы и свойства к существующим классам, структурам или перечислениям без изменения исходного кода.
extension String {
func reverse() -> String {
return String(self.reversed())
}
}

let original = "hello"
let reversed = original.reverse()
print(reversed) // "olleh"


🟠Делегирование
Делегирование передает ответственность за выполнение задач другому объекту, создавая гибкие и переиспользуемые компоненты.
protocol PrinterDelegate: AnyObject {
func printerDidFinishPrinting(_ printer: Printer)
}

class Printer {
weak var delegate: PrinterDelegate?

func printDocument() {
print("Printing document...")
delegate?.printerDidFinishPrinting(self)
}
}

class PrintManager: PrinterDelegate {
func printerDidFinishPrinting(_ printer: Printer) {
print("Document printing completed.")
}
}

let printer = Printer()
let manager = PrintManager()

printer.delegate = manager
printer.printDocument()


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

Value type (тип значения) хранит данные непосредственно, и при копировании создаётся новый независимый экземпляр. Например, в C# типы `int` или `struct` копируются по значению.
Reference type (ссылочный тип) хранит ссылку на область памяти, где находятся данные, и при копировании копируется только ссылка, а не сами данные. Например, объекты классов разделяют одну и ту же память.
Разница проявляется при изменении данных: value type остаётся неизменным в копиях, а reference type отражает изменения во всех ссылках.


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

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

🚩Класс `User`

Класс User обычно представляет сущность пользователя в системе. Он может включать свойства и методы, специфичные для пользователя, такие как идентификатор, имя, адрес электронной почты и методы для управления этими данными.
class User {
var id: Int
var name: String
var email: String

init(id: Int, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}

func updateEmail(newEmail: String) {
self.email = newEmail
}
}


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

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

🚩Класс `Data`

Класс Data чаще всего используется для представления необработанных данных или байтов. В Swift, например, Data — это структура из Foundation, которая предоставляет интерфейс для работы с бинарными данными.
import Foundation

let string = "Hello, World!"
if let data = string.data(using: .utf8) {
// Преобразование строки в Data
print(data)
}

let jsonString = "{\"name\": \"John\", \"age\": 30}"
if let jsonData = jsonString.data(using: .utf8) {
// Преобразование JSON-строки в Data
do {
if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
print(jsonObject)
}
} catch {
print("Ошибка парсинга JSON: \(error)")
}
}


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

🟠Представляет необработанные данные или байты.
🟠Используется для работы с файловыми данными, сетевыми данными, сериализацией и десериализацией данных.
🟠В основном используется для манипуляций с бинарными данными и передачи данных.

🚩Ключевые различия

🟠Назначение и область применения
User: Представляет конкретную сущность пользователя в системе. Используется для управления и хранения данных о пользователе.
Data: Представляет необработанные данные или байты. Используется для операций с бинарными данными, таких как чтение и запись файлов, сетевые операции и сериализация.

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

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

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1😁1
🤔 В чем суть оптимизации copy on write?

Copy on Write (COW) — это оптимизация, которая откладывает копирование данных до тех пор, пока они не будут изменены. В Swift, структуры и коллекции используют эту технику, чтобы избежать ненужных копий, если данные остаются неизменными. Когда структура или коллекция копируется, реальное копирование происходит только при попытке изменить данные, что снижает накладные расходы. Это помогает улучшить производительность и снизить использование памяти.

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

Приложения на Swift могут быть массивными из-за нескольких факторов:

🚩Причины

🟠Стандартная библиотека
Включает много функций и структур данных, что увеличивает размер бинарного файла.
🟠Архитектура приложения
Современные приложения часто используют множество внешних библиотек и фреймворков, добавляющих объем.
🟠Поддержка нескольких архитектур
Компиляция для разных архитектур (например, arm64, x86_64) увеличивает размер исполняемого файла.
🟠Ресурсы и медиафайлы
Большое количество изображений, видео и аудиофайлов увеличивают размер приложения.
🟠Символы отладки
Включение символов отладки для разработки и анализа сбоев добавляет объем.
🟠Статические библиотеки
Статические библиотеки увеличивают размер исполняемого файла по сравнению с динамическими.
🟠Кросс-компиляция
Поддержка старых версий iOS требует включения дополнительных библиотек и кода.

🚩Оптимизация размера

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

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

Value types в Swift — это типы данных, которые копируются при передаче в другую переменную или константу. Примеры value types включают структуры (struct), перечисления (enum) и встроенные типы данных, такие как Int и String. Когда вы изменяете копию value type, оригинальная переменная остаётся неизменной. Это поведение помогает избегать неожиданных изменений данных при работе с несколькими переменными.

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

🟠Побочные эффекты
PO вызывает методы description или debugDescription, которые могут изменять состояние объекта.

🟠Производительность
Тяжелые вычисления в методах description или debugDescription могут замедлить отладку.

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

🟠Краш приложения
Ошибки в методах description или debugDescription могут привести к сбоям при использовании PO.

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

🚩Примеры проблем

Побочные эффекты
class DangerousObject {
var counter = 0
var description: String {
counter += 1 // Изменение состояния
return "Counter: \(counter)"
}
}


Производительность
class HeavyObject {
var description: String {
let result = (0..<1_000_000).map { $0 * $0 }.reduce(0, +)
return "Result: \(result)"
}
}


Проблемы с потоками
class ThreadUnsafeObject {
var data = [Int]()
var description: String {
return "Data count: \(data.count)"
}
}


Краш приложения
class CrashObject {
var description: String {
fatalError("Should not be called")
}
}


Зависания
class LockObject {
let lock = NSLock()
var description: String {
lock.lock()
defer { lock.unlock() }
return "Locked"
}
}


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

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

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

Это текстовый протокол для общения в реальном времени. Он позволяет пользователям обмениваться сообщениями в каналах (чат-румах) или через личные сообщения.

🚩Характеристики

🟠Каналы
Объединяют пользователей для обсуждения общих тем.
🟠Личные сообщения
Прямой обмен сообщениями между пользователями.
🟠Серверы
Поддерживают несколько каналов и управляют соединениями пользователей.
🟠Клиенты
Программы, используемые для подключения к IRC-серверам и участия в чатах.

🚩Примеры использования

🟠Подключение к IRC-серверу.
🟠Вход в канал (например, #example).
🟠Обмен сообщениями с другими пользователями в канале или через личные сообщения.

🚩Плюсы

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

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

Инкапсуляция реализуется через модификаторы доступа (private, fileprivate, internal, public, open), ограничивающие доступ к свойствам и методам. Это позволяет контролировать, какие части кода могут изменять данные объекта.

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

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

🚩Механизмы реализации Synchronized

Различные механизмы синхронизации реализуют Synchronized по-разному, но общая идея заключается в использовании блокировок (локов), чтобы обеспечить эксклюзивный доступ к ресурсу.

🟠NSLock
Это простая блокировка, предоставляемая Foundation framework в Swift:
class ThreadSafeClass {
private var internalState = 0
private let lock = NSLock()

func increment() {
lock.lock()
internalState += 1
lock.unlock()
}

func getState() -> Int {
lock.lock()
let state = internalState
lock.unlock()
return state
}
}


🟠DispatchQueue
DispatchQueue позволяет организовать выполнение кода в синхронном или асинхронном режиме.
class ThreadSafeClass {
private var internalState = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")

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

func getState() -> Int {
return queue.sync {
internalState
}
}
}


🟠objc_sync_enter / objc_sync_exit
Эти функции используются для синхронизации в Objective-C и могут быть использованы в Swift.
class ThreadSafeClass: NSObject {
private var internalState = 0

func increment() {
objc_sync_enter(self)
internalState += 1
objc_sync_exit(self)
}

func getState() -> Int {
objc_sync_enter(self)
let state = internalState
objc_sync_exit(self)
return state
}
}


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

Hashable — это протокол, позволяющий объектам быть хэшируемыми для использования в структурах данных, таких как Set или Dictionary. Он требует реализации метода hash(into:).

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

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

🚩Как работают

🟠Аллокация (выделение памяти)
Статическая аллокация: Память выделяется во время компиляции и существует на протяжении всего времени выполнения программы. Используется для глобальных и статических переменных.
int globalVar = 10; // Статическая память     


Стековая аллокация: Память выделяется при вызове функции и освобождается при выходе из функции. Используется для локальных переменных.
void function() {
int localVar = 20; // Стековая память
}


Куча (динамическая аллокация): Память выделяется по запросу во время выполнения программы и освобождается вручную (в языках с ручным управлением памятью) или автоматически (в языках с автоматическим управлением памятью, например, через сборщик мусора).
int *ptr = (int*)malloc(sizeof(int) * 10); // Выделение памяти в куче
free(ptr); // Освобождение памяти


🟠Деаллокация (освобождение памяти)
Вручную: Программист отвечает за освобождение памяти, выделенной в куче.
free(ptr);     


Автоматически: Сборщик мусора (Garbage Collector) автоматически освобождает память, которая больше не используется.
// В Java нет необходимости освобождать память вручную.     


🚩Примеры

C/C++ (ручное управление памятью):
#include <stdio.h>
#include <stdlib.h>

int main() {
int *arr = (int*)malloc(sizeof(int) * 5); // Выделение памяти
if (arr == NULL) {
// Ошибка выделения памяти
return 1;
}
// Использование массива
for (int i = 0; i < 5; i++) {
arr[i] = i;
}
// Освобождение памяти
free(arr);
return 0;
}


Python (автоматическое управление памятью):
def create_list():
my_list = [i for i in range(5)] # Выделение памяти автоматически
return my_list # Память освобождается автоматически, когда объект больше не используется

my_list = create_list()
print(my_list)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤔1
🤔 Для чего опционал нужен в Swift?

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

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

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

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

🟠Автоматическая генерация документации
JSDoc позволяет автоматически создавать HTML-документацию из аннотированных комментариев в коде.
🟠Поддержка типов и параметров
JSDoc позволяет описывать типы данных параметров и возвращаемых значений функций.
🟠Описание функций, методов и классов
JSDoc используется для документирования всех аспектов кода, включая функции, методы, классы и модули.

/**
* Adds two numbers together.
* @param {number} a - The first number.
* @param {number} b - The second number.
* @returns {number} The sum of the two numbers.
*/
function add(a, b) {
return a + b;
}

/**
* Represents a person.
* @class
*/
class Person {
/**
* Creates a person.
* @param {string} name - The name of the person.
* @param {number} age - The age of the person.
*/
constructor(name, age) {
this.name = name;
this.age = age;
}

/**
* Greets someone.
* @param {string} [greetName='Stranger'] - The name of the person to greet.
* @returns {string} The greeting message.
*/
greet(greetName = 'Stranger') {
return `Hello, ${greetName}! My name is ${this.name}.`;
}
}


🚩Основные теги JSDoc

@param — Описание параметров функции.
@returns — Описание возвращаемого значения функции.
@class — Описание класса.
@constructor — Описание конструктора класса.
@typedef — Описание типа данных.

🚩Плюсы

Улучшение понимания кода
Комментарии JSDoc помогают другим разработчикам быстрее понять структуру и назначение кода.
Автоматическая документация
Генерация документации упрощает поддержание актуальности документации и кода.
Статический анализ кода
Некоторые инструменты могут использовать JSDoc для улучшения статического анализа кода, предоставляя более точные подсказки и проверки типов.

🚩Генерация документации

Для генерации документации с использованием JSDoc требуется установить и использовать инструмент командной строки JSDoc.

1⃣Установка JSDoc
npm install -g jsdoc   


2⃣Генерация документации
jsdoc yourJavaScriptFile.js   


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

Основные способы: принудительное развертывание (!), опциональная привязка (if let), guard let, использование оператора ?? для значений по умолчанию.

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

Да, в JavaScript, а также в других языках программирования, концепция Event Emitter (или Event Dispatcher) используется для работы с событиями и позволяет компонентам взаимодействовать друг с другом, подписываясь на события и реагируя на них. В JavaScript это часто реализуется с использованием колбэков.

🚩Event Emitter в JavaScript

В JavaScript Event Emitter часто используется с помощью библиотеки events, которая встроена в Node.js. Вот как это работает

1⃣Создание EventEmitter и подписка на события
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();

// Подписка на событие 'event'
eventEmitter.on('event', (message) => {
console.log(`Received event with message: ${message}`);
});


2⃣Инициация события
// Инициация события 'event'
eventEmitter.emit('event', 'Hello, World!');


🚩Event Emitter в браузере

В браузере события также часто обрабатываются с использованием колбэков через API, такие как addEventListener.

1⃣Добавление обработчика события
const button = document.getElementById('myButton');

// Подписка на событие 'click'
button.addEventListener('click', () => {
console.log('Button clicked!');
});


2⃣Инициация события (напрямую из кода)
// Инициация события 'click'
button.click();


🚩Реализация собственного EventEmitter

Можно создать собственный класс EventEmitter, который будет использовать колбэки для обработки событий.
class EventEmitter {
constructor() {
this.events = {};
}

on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}

emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(...args));
}
}

off(event, listener) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(l => l !== listener);
}
}
}

// Использование:
const emitter = new EventEmitter();

// Подписка на событие
emitter.on('message', (msg) => {
console.log(`Message: ${msg}`);
});

// Инициация события
emitter.emit('message', 'Hello, Event Emitter!');


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

Ключ должен быть типом, реализующим протокол Hashable, а значение может быть любым типом.

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

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

🚩Признаки DDD

🟠Доменная модель
Ubiquitous Language: Общий язык, используемый всей командой.
Доменные объекты: Сущности, значимые объекты, агрегаты, доменные события.

🟠Слои архитектуры
Доменный слой: Содержит модели, агрегаты, репозитории, доменные сервисы.
Слой приложений: Управляет потоками работы и координирует доменные объекты.
Инфраструктурный слой: Реализация репозиториев, доступ к базам данных.
Презентационный слой: Взаимодействие с пользователем.

🟠Репозитории и фабрики
Репозитории: Обеспечивают доступ к агрегатам.
Фабрики: Управляют созданием сложных объектов.

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