Swift | Вопросы собесов
2.23K subscribers
30 photos
964 links
Download Telegram
🤔 Что из себя представляет структура данных stack?

Stack (стек) – это структура данных, работающая по принципу LIFO (Last In, First Out – "последним пришел, первым ушел").

🚩Пример реализации стека в Swift

В Swift нет встроенного стека (кроме Array), но можно создать свой:
struct Stack<T> {
private var elements: [T] = []

mutating func push(_ item: T) {
elements.append(item)
}

mutating func pop() -> T? {
return elements.popLast() // Удаляет и возвращает верхний элемент
}

func peek() -> T? {
return elements.last // Возвращает верхний элемент без удаления
}

func isEmpty() -> Bool {
return elements.isEmpty
}
}

// Пример использования:
var stack = Stack<Int>()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.pop()!) // 30
print(stack.peek()!) // 20
print(stack.isEmpty()) // false


🚩Где используется стек?

Обратный порядок выполнения (рекурсия) – стек вызовов функций.
Алгоритмы (обратная польская нотация, DFS – поиск в глубину)
История действий (назад-вперед в браузере, отмена в редакторе).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 В чём разница между Greetings 3 и Greetings 1?

Это вопрос требует контекста (возможно, из демонстрационного проекта или тестового задания), но, вероятно, имеются в виду различные реализации приветствия или экраны. Greetings 1 может быть обычным экраном, а Greetings 3 — использовать, например, локализацию, зависимости, или иметь другой подход к отображению (композиционный layout, новые API и пр.). Уточни, если речь шла о чём-то конкретном.


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

В Swift есть несколько инструментов для работы с многопоточностью и параллельным выполнением кода. Вот основные из них:

🟠GCD (Grand Central Dispatch) – главный инструмент для потоков
GCD – это низкоуровневая технология, позволяющая управлять задачами (тасками) в очередях (DispatchQueue).
DispatchQueue.global(qos: .background).async {
print("Фоновый поток")

DispatchQueue.main.async {
print("Вернулись в главный поток")
}
}


🟠OperationQueue – более удобный API для задач
OperationQueue – это более гибкая и объектно-ориентированная альтернатива GCD.
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2 // Ограничение на 2 задачи одновременно

queue.addOperation {
print("Операция 1")
}

queue.addOperation {
print("Операция 2")
}


🟠Actors – безопасная работа с потоками в Swift 5.5+
С actor можно работать с потоками без гонок данных, потому что все его свойства защищены от одновременного доступа.
actor Counter {
private var value = 0

func increment() {
value += 1
}

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

let counter = Counter()

Task {
await counter.increment()
print(await counter.getValue()) // Потокобезопасный доступ
}


🟠Task & Async/Await (Swift 5.5+) – современный подход к асинхронности
С async/await код становится читаемым и удобным.
func fetchData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 секунда задержки
return "Данные загружены"
}

Task {
let result = await fetchData()
print(result)
}


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

UIKit работает только в главном потоке (Main Thread). Если нужно выполнить тяжелую задачу (сетевой запрос, обработку данных):
- Используют
DispatchQueue.global(qos:) (фоновый поток).
- После выполнения обновляют UI через DispatchQueue.main.async {}.
Если попытаться обновить UI в фоновом потоке, возможны ошибки или некорректное поведение.


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

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

🟠Что значит "функция типа T"?
Функция в Swift — это тоже тип данных.
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}


Тип этой функции
(Int, Int) -> Int


🟠Пример: оператор `+` для функций
Допустим, у нас есть две функции, и мы хотим, чтобы оператор + создавал новую функцию, объединяя их поведение.
import Foundation

// Функция типа (Int) -> Int
func double(_ x: Int) -> Int {
return x * 2
}

func increment(_ x: Int) -> Int {
return x + 1
}

// Перегружаем оператор + для функций (Int) -> Int
func + (lhs: @escaping (Int) -> Int, rhs: @escaping (Int) -> Int) -> (Int) -> Int {
return { x in rhs(lhs(x)) } // Сначала вызываем первую, затем вторую
}

// Используем оператор
let combinedFunction = double + increment

print(combinedFunction(3)) // (3 * 2) + 1 = 7


🟠Пример: оператор `*` для функций
Можно сделать оператор *, который применяет функцию несколько раз.
// Перегружаем оператор * для дублирования применения функции
func * (lhs: @escaping (Int) -> Int, rhs: Int) -> (Int) -> Int {
return { x in
var result = x
for _ in 0..<rhs {
result = lhs(result)
}
return result
}
}

// Используем оператор
let tripleDouble = double * 3

print(tripleDouble(2)) // (2 * 2) * 2 * 2 = 16


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

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

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

В iOS существует несколько способов вёрстки пользовательского интерфейса. Каждый из них имеет свои плюсы и минусы в зависимости от проекта.

🟠Interface Builder (Storyboard & XIB)
Используется: визуальный редактор в Xcode.
Storyboard
- Позволяет создавать весь UI в одном файле .storyboard.
- Поддерживает Auto Layout и Size Classes для адаптивного дизайна.
- Можно настраивать Segue (переходы между экранами).

🟠Верстка кодом (без Storyboard)
Используется: Полностью программная вёрстка без использования Interface Builder.
let button = UIButton()
button.setTitle("Нажми", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)

NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])


🟠SwiftUI – декларативный подход
Используется: Современный способ верстки с декларативным синтаксисом.
struct ContentView: View {
var body: some View {
VStack {
Text("Привет, SwiftUI!")
.font(.largeTitle)
Button("Нажми меня") {
print("Кнопка нажата")
}
}
}
}


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

Ссылочные типы (class) хранятся в куче (heap), а переменные содержат ссылки на них. Значимые типы (struct, enum) хранятся в стеке, если не вложены в ссылочные, и копируются при передаче.


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

В Swift словарь (Dictionary) представляет собой структуру данных, которая хранит пары ключ-значение и обеспечивает быстрый доступ к значениям по ключу (O(1) в среднем). Но если бы мы хотели реализовать словарь на основе массива, то пришлось бы использовать линейный поиск, что делает операции менее эффективными (O(n)).

🚩Реализация словаря через массив кортежей

Один из простых способов создать словарь на базе массива — использовать массив кортежей (ключ, значение).
struct ArrayDictionary<Key: Equatable, Value> {
private var items: [(Key, Value)] = [] // Храним пары ключ-значение

// Получение значения по ключу
func value(for key: Key) -> Value? {
for (k, v) in items {
if k == key {
return v
}
}
return nil
}

// Добавление или обновление значения
mutating func insert(value: Value, for key: Key) {
for i in 0..<items.count {
if items[i].0 == key {
items[i].1 = value // Обновляем значение, если ключ уже есть
return
}
}
items.append((key, value)) // Добавляем новую пару
}

// Удаление элемента по ключу
mutating func remove(for key: Key) {
items.removeAll { $0.0 == key }
}
}

// Пример использования
var myDict = ArrayDictionary<String, Int>()
myDict.insert(value: 42, for: "age")
myDict.insert(value: 30, for: "height")

print(myDict.value(for: "age")!) // 42
myDict.remove(for: "age")
print(myDict.value(for: "age")) // nil


🚩Оптимизация: Использование бинарного поиска

Если мы отсортируем массив по ключам, можно использовать бинарный поиск (O(log n)) для ускорения поиска ключа.
struct SortedArrayDictionary<Key: Comparable, Value> {
private var items: [(Key, Value)] = []

// Бинарный поиск индекса ключа
private func index(of key: Key) -> Int? {
var left = 0
var right = items.count - 1
while left <= right {
let mid = (left + right) / 2
if items[mid].0 == key {
return mid
} else if items[mid].0 < key {
left = mid + 1
} else {
right = mid - 1
}
}
return nil
}

// Получение значения по ключу
func value(for key: Key) -> Value? {
if let index = index(of: key) {
return items[index].1
}
return nil
}

// Вставка с сохранением сортировки
mutating func insert(value: Value, for key: Key) {
if let index = index(of: key) {
items[index].1 = value
} else {
items.append((key, value))
items.sort { $0.0 < $1.0 } // Сортируем после вставки
}
}
}

// Использование
var sortedDict = SortedArrayDictionary<String, Int>()
sortedDict.insert(value: 50, for: "b")
sortedDict.insert(value: 20, for: "a")
sortedDict.insert(value: 70, for: "c")

print(sortedDict.value(for: "b")!) // 50


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

Стек создается при запуске потока. Он выделяется для хранения информации о вызовах функций, аргументах, возвращаемых адресах и локальных переменных. Каждый поток имеет свой стек.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🤔 Что такое очередь?

Структура данных, организованная по принципу FIFO (First In, First Out).
1. В программировании это механизм для выполнения задач последовательно или параллельно.
2. Примеры: DispatchQueue в GCD или системные очереди для обработки событий.


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

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

🟠Что значит "функция типа T"?
Функция в Swift — это тоже тип данных.
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}


Тип этой функции
(Int, Int) -> Int


🟠Пример: оператор `+` для функций
Допустим, у нас есть две функции, и мы хотим, чтобы оператор + создавал новую функцию, объединяя их поведение.
import Foundation

// Функция типа (Int) -> Int
func double(_ x: Int) -> Int {
return x * 2
}

func increment(_ x: Int) -> Int {
return x + 1
}

// Перегружаем оператор + для функций (Int) -> Int
func + (lhs: @escaping (Int) -> Int, rhs: @escaping (Int) -> Int) -> (Int) -> Int {
return { x in rhs(lhs(x)) } // Сначала вызываем первую, затем вторую
}

// Используем оператор
let combinedFunction = double + increment

print(combinedFunction(3)) // (3 * 2) + 1 = 7


🟠Пример: оператор `*` для функций
Можно сделать оператор *, который применяет функцию несколько раз.
// Перегружаем оператор * для дублирования применения функции
func * (lhs: @escaping (Int) -> Int, rhs: Int) -> (Int) -> Int {
return { x in
var result = x
for _ in 0..<rhs {
result = lhs(result)
}
return result
}
}

// Используем оператор
let tripleDouble = double * 3

print(tripleDouble(2)) // (2 * 2) * 2 * 2 = 16


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

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


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

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

🚩Проблемы

🟠Утечки памяти (Retain Cycles)
Одной из самых распространенных проблем является утечка памяти из-за циклов удержания (retain cycles). Это происходит, когда два или более объекта удерживают ссылки друг на друга, препятствуя освобождению памяти. В этом примере closure захватывает self, что создает цикл удержания: MyClass держит сильную ссылку на closure, а closure держит сильную ссылку на self.
class MyClass {
var value: Int = 0
var closure: (() -> Void)?

func setupClosure() {
closure = {
self.value += 1
}
}
}

let instance = MyClass()
instance.setupClosure()


🟠Непредсказуемое поведение и условия гонки (Race Conditions)
Когда замыкания захватывают изменяемый контекст, это может привести к условиям гонки и непредсказуемому поведению, особенно при работе в многопоточном окружении. Если метод increment вызывается из разных потоков, это может привести к условиям гонки и некорректному изменению значения count.
class Counter {
var count = 0

func increment() {
DispatchQueue.global().async {
self.count += 1
}
}
}

let counter = Counter()
counter.increment()


🟠Задержки в освобождении ресурсов
Если замыкания захватывают тяжелые ресурсы (например, файлы, сети), это может привести к задержкам в их освобождении, что может негативно сказаться на производительности приложения. Если FileHandler освобождается, но замыкание все еще захватывает file, это может привести к задержке в освобождении файлового дескриптора.
class FileHandler {
var file: File?

func processFile() {
DispatchQueue.global().async {
self.file?.read()
}
}
}


🟠Потеря захваченных данных
Когда используется слабая ссылка (weak), замыкание может обнаружить, что захваченный объект освобожден, что приводит к тому, что слабая ссылка становится nil. Это требует дополнительных проверок и обработки.
class MyClass {
var value: Int = 0
var closure: (() -> Void)?

func setupClosure() {
closure = { [weak self] in
guard let strongSelf = self else { return }
strongSelf.value += 1
}
}
}


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

Необходимо, чтобы объект был хешируемым и имел корректно реализованное сравнение на равенство. В разных языках это делается через имплементацию hash и eq, Hashable, или Comparable. В случае классов — важно, чтобы их экземпляры имели неизменяемые поля, влияющие на ключ.


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

Мьютекс (от англ. "mutex" - mutual exclusion, взаимное исключение) — это механизм синхронизации, используемый в многопоточном программировании для предотвращения одновременного доступа нескольких потоков к общим ресурсам, таким как переменные, структуры данных или файлы. Он помогает избежать состояния гонки (race condition), когда результат выполнения программы зависит от неопределённого порядка доступа потоков к ресурсу.

🚩Основные концепции мьютекса

🟠Взаимное исключение
Мьютекс обеспечивает доступ к общему ресурсу только одному потоку в каждый момент времени. Когда один поток захватывает мьютекс, другие потоки должны ждать, пока мьютекс не будет освобождён.

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

🚩Пример использования мьютекса в Swift

import Foundation

class SafeCounter {
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
}
}

let counter = SafeCounter()
DispatchQueue.global().async {
for _ in 0..<1000 {
counter.increment()
}
}

DispatchQueue.global().async {
for _ in 0..<1000 {
counter.increment()
}
}

// Подождём немного, чтобы дать потокам закончить работу
Thread.sleep(forTimeInterval: 1)
print("Final counter value: \(counter.getValue())")


🚩Плюсы и минусы

Безопасность данных
Мьютексы защищают общие ресурсы от одновременного доступа, предотвращая повреждение данных.

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

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

Производительность
Чрезмерное использование мьютексов может привести к снижению производительности из-за увеличения времени ожидания потоков.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В каких случаях лучше использовать SQLite, а в каких Core Data?

Core Data идеально подходит, если вы хотите работать с объектами и использовать такие функции, как связи, undo, интеграция с UI и валидации. Она абстрагирует от SQL и позволяет концентрироваться на логике приложения.
SQLite стоит использовать, когда:
- нужна максимальная производительность и контроль;
- требуется небольшой размер хранилища;
- предпочтительна работа с чистыми SQL-запросами;
- не нужны объекты, а только таблицы и строки.
Если говорить просто: Core Data — это удобство и объектная модель, SQLite — гибкость и контроль.


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

Перед вызовом layoutIfNeeded() или layoutSubviews() в iOS-приложении, нужно изменить значение констрейнта и вызвать анимацию, если необходимо. Вот основные шаги:

🟠Обновление значения констрейнта
Перед вызовом layoutIfNeeded(), измените свойство констрейнта (например, constant у NSLayoutConstraint).
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
@IBOutlet weak var heightConstraint: NSLayoutConstraint!

override func viewDidLoad() {
super.viewDidLoad()

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.changeButtonHeight()
}
}

func changeButtonHeight() {
heightConstraint.constant = 100 // Меняем значение констрейнта
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded() // Перестраиваем макет
}
}
}


🟠Если меняется набор констрейнтов
Если нужно удалить/добавить констрейнты, используйте `activate()` / `deactivate()`.
var expanded = false

@IBOutlet weak var smallHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var largeHeightConstraint: NSLayoutConstraint!

func toggleHeight() {
expanded.toggle()

if expanded {
NSLayoutConstraint.deactivate([smallHeightConstraint])
NSLayoutConstraint.activate([largeHeightConstraint])
} else {
NSLayoutConstraint.deactivate([largeHeightConstraint])
NSLayoutConstraint.activate([smallHeightConstraint])
}

UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}


🟠Если работа идёт в `viewDidLoad()`
Во viewDidLoad() элементы ещё не отрисованы, поэтому layoutIfNeeded() не сработает. Используйте viewDidAppear() или вызовите layoutIfNeeded() после view.layoutIfNeeded().
override func viewDidLoad() {
super.viewDidLoad()
heightConstraint.constant = 100
view.layoutIfNeeded() // НЕ обновит макет, потому что он ещё не загружен
}


Решение
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

heightConstraint.constant = 100
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}


Разница между layoutIfNeeded() и setNeedsLayout()
heightConstraint.constant = 100
view.setNeedsLayout() // Обновление произойдет на следующем цикле рендера


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

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


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