Swift | Вопросы собесов
2.13K subscribers
28 photos
955 links
Download Telegram
🤔 Когда появляется Sitable?

Это состояние интерфейса, в котором пользовательский ввод не вызывает изменений, но при этом интерфейс остается активным.
Используется в UI/UX для предотвращения некорректного поведения интерфейса, например:
- Во время загрузки данных
- В процессе валидации формы
- При временной блокировке кнопок


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

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

🚩Как работают push-уведомления

1⃣Регистрация устройства
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения push-уведомлений. Для этого приложение отправляет запрос к Apple Push Notification Service (APNs) с запросом на получение уникального токена устройства (device token).

2⃣Получение токена устройства
APNs генерирует уникальный токен для устройства и отправляет его обратно приложению. Приложение затем передает этот токен на свой сервер.

3⃣Отправка уведомления на сервер
Когда необходимо отправить push-уведомление, сервер приложения формирует сообщение, включающее содержимое уведомления и токен устройства, и отправляет его на APNs.

4⃣Доставка уведомления
APNs принимает сообщение от сервера, определяет устройство по токену и отправляет уведомление на это устройство.

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

🚩Пример кода для регистрации устройства

В AppDelegate
import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Запрос разрешения на отправку уведомлений
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
return true
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Преобразуем токен в строку
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")

// Отправляем токен на сервер
// serverAPI.registerDeviceToken(token)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
}


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

Ссылки определяют управление памятью и временем жизни объектов. Основные типы:
1. Сильная (strong reference) – объект остается в памяти, пока на него есть ссылка
2. Слабая (weak reference) – не предотвращает сборку мусора
3. Небезопасная (unowned) – слабая ссылка без автоматического обнуления
4. Циклические ссылки (strong reference cycles) – могут приводить к утечкам памяти


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

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

🚩Основы наследования

🟠Определение базового класса
Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами.

🟠Создание подкласса
Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие.

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

🟠Предотвращение переопределения
Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова final. Если метод, свойство или индексатор объявлен как final, то он не может быть переопределён в подклассе.
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// Этот метод будет переопределен в подклассах, если необходимо
}
}

class Bicycle: Vehicle {
var hasBasket = false
}

class Car: Vehicle {
var gear = 1
final func drive() {
print("Car is moving")
}
override func makeNoise() {
print("Vroom!")
}
}


🚩Использование super

Подклассы могут вызывать методы своего суперкласса с помощью ключевого слова super. Это позволяет подклассам расширять, а не заменять поведение суперкласса.

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

Это способ размещения элементов в интерфейсе. Основные варианты:
1. Absolute Layout – жесткое позиционирование элементов
2. Relative Layout – элементы позиционируются относительно друг друга
3. Linear Layout – элементы располагаются по одной оси
4. Grid Layout – элементы располагаются в сетке
5. Constraint Layout – гибкое размещение с ограничениями (используется в Android)
6. Flexbox/Grid (CSS) – адаптивная верстка в веб-разработке


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

Да, отслеживание статуса задачи в DispatchWorkItem может быть полезным, но это зависит от требований приложения.

🟠Когда это полезно?
Если задача может быть отменена (cancel())
Если выполнение задачи можно приостановить или продолжить
Если нужно проверить завершение перед выполнением следующего действия*
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Запускаем задачу
DispatchQueue.global().async(execute: workItem)

// Отмена перед выполнением
workItem.cancel()

// Проверяем статус выполнения
if workItem.isCancelled {
print("Задача отменена")
} else {
print("Задача выполнена")
}


🟠Можно ли проверить, завершена ли задача?
В DispatchWorkItem нет метода проверки завершения.
Но можно вручную отслеживать завершение с помощью notify:
let workItem = DispatchWorkItem {
print("Задача выполняется")
}

// Сообщаем о завершении
workItem.notify(queue: .main) {
print("Задача завершена")
}

DispatchQueue.global().async(execute: workItem)


🟠Надо ли всегда отслеживать статус?
Если задача короткая и простая → НЕ ОБЯЗАТЕЛЬНО.
Если задача важная, может быть отменена или зависит от других задач → ЛУЧШЕ ОТСЛЕЖИВАТЬ.

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

Layout определяет расположение элементов на экране, его выбор влияет на производительность и удобство поддержки кода.
Плюсы:
- Гибкость – позволяет адаптировать UI под разные размеры экранов.
- Читаемость кода – декларативные подходы (например, Flexbox, ConstraintLayout) упрощают понимание.
- Адаптивность – некоторые виды layout автоматически подстраиваются под содержимое.
- Кроссплатформенность – разметка может быть использована на разных устройствах.
Минусы:
- Производительность – сложные иерархии могут замедлять рендеринг.
- Сложность отладки – в сложных layout'ах трудно понять, почему элемент занимает именно такое место.
- Ограниченность возможностей – некоторые системы layout могут не поддерживать желаемые анимации и трансформации.


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

Принцип OCP (Open-Closed Principle) гласит:
"Программные сущности должны быть открыты для расширения, но закрыты для модификации."
Это значит, что код должен позволять добавлять новый функционал без изменения существующего кода.

🚩Почему это важно?

Меньше багов – изменения не ломают старый код.
Лучшая поддержка – новый функционал добавляется без переписывания старого.
Гибкость – можно расширять систему без изменения её базовой логики.

🚩Пример нарушения принципа OCP

Допустим, у нас есть класс, который рисует фигуры:
class ShapeDrawer {
func draw(shape: String) {
if shape == "circle" {
print("Рисуем круг")
} else if shape == "square" {
print("Рисуем квадрат")
}
}
}


🚩Как исправить? Используем OCP!

Лучше использовать наследование или протоколы, чтобы расширять функциональность, не меняя существующий код:
protocol Drawable {
func draw()
}

class Circle: Drawable {
func draw() {
print("Рисуем круг")
}
}

class Square: Drawable {
func draw() {
print("Рисуем квадрат")
}
}

class ShapeDrawer {
func draw(shape: Drawable) {
shape.draw()
}
}


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

Обе ссылки используются для предотвращения циклических зависимостей и утечек памяти, но есть важные отличия.
Weak (слабая ссылка):
- Не увеличивает счетчик ссылок.
- Автоматически обнуляется (nil), когда объект удаляется из памяти.
- Используется, если объект может стать nil в будущем.
Unowned (небезопасная слабая ссылка):
- Не увеличивает счетчик ссылок.
- Не обнуляется автоматически, что может привести к crash, если объект удален.
- Используется, если объект гарантированно существует до конца жизненного цикла ссылки.


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

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

🚩`lazy var` (ленивые свойства)
Обычное свойство инициализируется сразу, а lazy – только при первом вызове.
class Example {
lazy var expensiveObject: Data = {
print("Объект создан!")
return Data()
}()
}

let obj = Example()
print("Объект ещё не создан")
_ = obj.expensiveObject // Только теперь создастся


🚩`LazySequence` и `LazyCollection`

Если вы хотите избежать лишних вычислений, можно использовать ленивую последовательность:
let numbers = (1...1000).lazy.map { $0 * 2 } // Не вычисляется сразу!
print(numbers.first!) // Только теперь вычисляется первый элемент


🚩`LazyVStack`, `LazyHStack`, `LazyGrid` (SwiftUI)

В отличие от обычных VStack и HStack, ленивые версии создают элементы только при прокрутке.
ScrollView {
LazyVStack {
ForEach(0..<1000) { index in
Text("Элемент \(index)")
}
}
}


🚩`UITableView` и `UICollectionView` (UIKit)

Они работают по принципу переиспользования ячеек, загружая их только когда нужно.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Строка \(indexPath.row)"
return cell
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Зачем нужны сильные (Strong) ссылки?

Сильные ссылки увеличивают счетчик ссылок (reference count), что предотвращает удаление объекта сборщиком мусора.
Используются, когда:
- Объект должен оставаться в памяти, пока на него есть хотя бы одна ссылка.
- В retain cycles (если используются неправильно, могут привести к утечкам памяти).
- Создаются объекты, жизненный цикл которых контролируется вручную.


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

В Swift все типы данных делятся на два вида по семантике хранения и передачи:

🚩Значимая семантика (Value Semantics)

Структуры (struct), перечисления (enum) и кортежи (tuple) передаются по значению, то есть каждое присваивание создаёт копию объекта.
struct User {
var name: String
}

var user1 = User(name: "Alice")
var user2 = user1 // Копия!

user2.name = "Bob"

print(user1.name) // "Alice" (НЕ изменилось)
print(user2.name) // "Bob"


🚩Ссылочная семантика (Reference Semantics)

Классы (class), акторы (actor) и замыкания (closure) передаются по ссылке, то есть несколько переменных могут ссылаться на один и тот же объект.
class User {
var name: String
init(name: String) {
self.name = name
}
}

var user1 = User(name: "Alice")
var user2 = user1 // Передача ссылки!

user2.name = "Bob"

print(user1.name) // "Bob" (ИЗМЕНИЛОСЬ!)
print(user2.name) // "Bob"


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
🤔 Зачем нужны слабые (Weak) ссылки?

Слабые ссылки используются, когда объект не должен предотвращать сборку мусора, например:
- Для delegate паттернов, чтобы избежать retain cycle.
- При кэшировании данных, если объект можно удалить.
- В иерархиях parent-child, если child не должен удерживать parent в памяти.


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

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

🚩Порождающие паттерны (Creational)

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

class iOSButton: Button {
func press() { print("iOS button pressed") }
}

class AndroidButton: Button {
func press() { print("Android button pressed") }
}

class ButtonFactory {
static func createButton(for os: String) -> Button {
return os == "iOS" ? iOSButton() : AndroidButton()
}
}

let button = ButtonFactory.createButton(for: "iOS")
button.press() // "iOS button pressed"


🟠Одиночка (Singleton)
Гарантирует, что у класса будет только один экземпляр.
class Database {
static let shared = Database() // Единственный экземпляр
private init() { }

func query() { print("Запрос в базу данных") }
}

Database.shared.query()


🟠Строитель (Builder)
Позволяет пошагово создавать сложные объекты.
class Burger {
var cheese = false
var bacon = false
}

class BurgerBuilder {
private var burger = Burger()

func addCheese() -> Self {
burger.cheese = true
return self
}

func addBacon() -> Self {
burger.bacon = true
return self
}

func build() -> Burger {
return burger
}
}

let myBurger = BurgerBuilder().addCheese().addBacon().build()
print(myBurger.cheese) // true
print(myBurger.bacon) // true


🚩Структурные паттерны (Structural)

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

🟠Адаптер (Adapter)
Позволяет совместить несовместимые интерфейсы.
protocol EuropeanSocket {
func provide220V()
}

class EuropeanPlug: EuropeanSocket {
func provide220V() { print("220V подано") }
}

class USPlug {
func provide110V() { print("110V подано") }
}

// Адаптер для американской вилки
class USAdapter: EuropeanSocket {
private let usPlug: USPlug

init(usPlug: USPlug) { self.usPlug = usPlug }

func provide220V() {
usPlug.provide110V()
print("Адаптация до 220V")
}
}

let adapter = USAdapter(usPlug: USPlug())
adapter.provide220V()
// "110V подано"
// "Адаптация до 220V"


🟠Декоратор (Decorator)
Динамически добавляет объекту новое поведение.
protocol Coffee {
func cost() -> Int
}

class SimpleCoffee: Coffee {
func cost() -> Int { return 100 }
}

// Декоратор "Молоко"
class MilkDecorator: Coffee {
private let coffee: Coffee

init(_ coffee: Coffee) { self.coffee = coffee }

func cost() -> Int {
return coffee.cost() + 30
}
}

let coffee = MilkDecorator(SimpleCoffee())
print(coffee.cost()) // 130


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Message используется только при тестировании или еще когда-то?

Это объект, передающий информацию между компонентами системы.
Используется не только для тестирования, но и в других сценариях:
- Во фреймворках типа RxSwift, Kotlin Flow и React – передача событий.
- При межпроцессном взаимодействии (IPC) – обмен данными между процессами.
- В Actor Model (например, Akka и Erlang) – распределенные вычисления.
- В iOS/Android приложениях – коммуникация между потоками (Handler, MessageQueue).


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

Объектно-ориентированное программирование (ООП) — это парадигма, основанная на концепции "объектов", которые могут содержать данные в виде полей (часто называемых атрибутами или свойствами) и код в виде процедур (часто называемых методами). ООП фокусируется на использовании объектов для моделирования реального мира (или абстракций), облегчая разработку и поддержку сложных программ. Существует четыре основных принципа:

🟠Инкапсуляция
Механизм ООП, который объединяет данные (атрибуты) и код (методы), манипулирующий этими данными, внутри одного объекта и скрывает детали реализации от внешнего использования. Это позволяет защитить внутреннее состояние объекта от прямого доступа извне и обеспечить контролируемый интерфейс для работы с этим объектом.

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

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

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

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

Это механизм в Apple Foundation, который позволяет использовать Core Foundation (CF) объекты в Objective-C и Swift без конвертации.
Пример:
- NSString и CFStringRef можно использовать взаимозаменяемо.
- NSArray и CFArrayRef можно передавать между Core Foundation и Foundation API.
Преимущества:
- Производительность – нет затрат на создание новых объектов.
- Гибкость – можно использовать Core Foundation объекты в коде.


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

В Swift есть несколько способов отлавливать и диагностировать ошибки в коде:

🚩Обработка ошибок через `do-catch`

Используется, если функция генерирует ошибку (throws).
enum LoginError: Error {
case wrongPassword
case userNotFound
}

func login(user: String, password: String) throws {
if user != "admin" { throw LoginError.userNotFound }
if password != "1234" { throw LoginError.wrongPassword }
}

do {
try login(user: "admin", password: "wrong")
} catch LoginError.wrongPassword {
print("Ошибка: Неверный пароль")
} catch {
print("Ошибка: \(error)")
}


🚩`assert()`, `precondition()`, `fatalError()` (для отладки)

Эти функции прерывают выполнение программы, если что-то пошло не так.
assert() (только в Debug)
let age = -5
assert(age >= 0, "Возраст не может быть отрицательным")


precondition() (работает в Release)
precondition(age >= 0, "Возраст не может быть отрицательным")


fatalError() (прерывает программу)
func getData() -> String {
fatalError("Метод ещё не реализован")
}


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

Это файл символов отладки, содержащий информацию о скомпилированном коде.
Используется для:
- Расшифровки crash logs, полученных от пользователей (Crashlytics, Sentry).
- Упрощения анализа stack trace в ошибках.
- Сопоставления машинного кода с исходным кодом.


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

Это возможность центрального процессора (ЦПУ) или программы выполнять несколько задач (потоков) одновременно. В контексте программирования она используется для улучшения производительности приложений за счёт параллельной обработки задач. Это особенно важно для задач, требующих интенсивных вычислений, или приложений, которые должны одновременно реагировать на множество входных данных, таких как пользовательский интерфейс.

🚩Основные понятия

🟠Поток (Thread)
Минимальная единица обработки, которая может быть выполнена операционной системой.

🟠Конкуренция (Concurrency)
Способность программы делать прогресс в нескольких задачах одновременно. Конкуренция достигается за счёт переключения между задачами.

🟠Параллелизм (Parallelism)
Способность программы выполнять несколько операций одновременно, используя множество процессоров или ядер.

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