Swift | Вопросы собесов
رفتن به کانال در Telegram
Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv
نمایش بیشتر2 196
مشترکین
+124 ساعت
-17 روز
-1330 روز
آرشیو پست ها
🤔 Что известно про Memory Graph (мемориграф)?
Memory Graph в Xcode показывает живые объекты и их связи. Это полезно для поиска retain cycles, обнаружения неосвобождённых контроллеров и анализа структуры объектов. Доступен во время отладки через Debug Navigator.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Что может быть ключом и значением для 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"]
Ставь 👍 и забирай 📚 Базу знаний🤔 Как работает UITableView?
- Использует реиспользуемые ячейки (dequeueReusableCell) для оптимизации памяти.
- Работает с делегатами (UITableViewDelegate) и источниками данных (UITableViewDataSource) для динамического обновления контента.
- Поддерживает разделы, перетаскивание, редактирование.
- Может быть обновлен с анимацией (reloadData, performBatchUpdates).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Зачем нужны слабые ссылки?
Слабые ссылки (weak references) играют важную роль в управлении памятью, особенно когда нужно предотвратить циклы сильных ссылок (retain cycles) и утечки памяти.
🚩Основные причины использования
🟠Предотвращение циклов сильных ссылок
Циклы сильных ссылок возникают, когда два объекта держат сильные ссылки друг на друга, что препятствует их освобождению из памяти. Слабые ссылки разрывают этот цикл, позволяя одному из объектов освобождаться.
class Person {
var name: String
weak var friend: Person?
init(name: String) {
self.name = name
}
}
var alice: Person? = Person(name: "Alice")
var bob: Person? = Person(name: "Bob")
alice?.friend = bob
bob?.friend = alice
alice = nil // Теперь объекты могут быть освобождены
bob = nil
🟠Избежание утечек памяти
Утечки памяти происходят, когда объекты, которые больше не нужны, не освобождаются из памяти. Слабые ссылки помогают избежать этих утечек, обеспечивая правильное освобождение памяти. Делегаты часто объявляются как слабые ссылки, чтобы избежать утечек памяти.
protocol TaskDelegate: AnyObject {
func taskDidFinish()
}
class Task {
weak var delegate: TaskDelegate?
func complete() {
delegate?.taskDidFinish()
}
}
class ViewController: TaskDelegate {
var task = Task()
init() {
task.delegate = self
}
func taskDidFinish() {
print("Task finished")
}
}
🟠Управление временными зависимостями
Слабые ссылки удобны для временных зависимостей, когда объект не должен удерживаться в памяти, если нет других сильных ссылок. Использование слабых ссылок для временных объектов.
class Cache {
weak var temporaryObject: SomeClass?
}
class SomeClass {
// Код класса
}
var cache = Cache()
var object = SomeClass()
cache.temporaryObject = object
object = SomeClass() // Старый объект удаляется, так как на него нет сильных ссылок
🚩Плюсы и минусы
➕Предотвращение циклов ссылок
Основное преимущество слабых ссылок заключается в их способности разрывать циклы ссылок, предотвращая утечки памяти.
➕Обеспечение корректного управления памятью
Слабые ссылки позволяют объектам освобождаться из памяти, когда на них больше нет сильных ссылок, что улучшает управление ресурсами.
➕Гибкость и безопасность
Использование слабых ссылок обеспечивает более гибкое и безопасное управление зависимостями между объектами.
➖Сложности управления
Необходимо учитывать, что слабые ссылки могут стать nil в любой момент, поэтому требуется дополнительная проверка.
➖Понимание жизненного цикла объектов
Требуется хорошее понимание жизненного цикла объектов и управления памятью, чтобы правильно использовать слабые ссылки.
Ставь 👍 и забирай 📚 Базу знаний🤔 Как запустить поток?
Запустить поток можно разными способами:
- Использовать асинхронную задачу или очередь, чтобы выполнить код в фоне.
- В многопоточной среде — создать новый поток, задачу или использовать пул потоков.
- В Swift это можно сделать с помощью DispatchQueue, Task или OperationQueue.
Важно помнить, что всё, что связано с UI, должно выполняться в основном потоке.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Какие паттерны знаешь?
Паттерны проектирования – это готовые решения частых задач, улучшающие структуру кода, его поддержку и масштабируемость.
🚩Порождающие паттерны (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
Ставь 👍 и забирай 📚 Базу знаний🤔 Зачем нужен UIView, если есть layer?
UIView — это высокоуровневая оболочка, которая управляет взаимодействием, событиями, отрисовкой, а CALayer — низкоуровневая графическая часть. Через UIView проще управлять UI и логикой, layer — для кастомной графики и анимаций.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Расскажи про классы
Классы — это ссылочные типы в Swift, которые позволяют создавать объекты с общими свойствами и методами. Они поддерживают наследование, работают с ARC (Automatic Reference Counting) и хранятся в куче (heap).
🚩Основные характеристики классов
🟠Ссылочный тип
Когда вы присваиваете класс другой переменной, копируется не сам объект, а ссылка на него. Изменения, сделанные через одну ссылку, затронут и другие.
🟠Хранятся в куче
В отличие от структур, которые хранятся в стеке, классы создают объекты в куче. Это позволяет передавать объекты между функциями без копирования.
🟠Automatic Reference Counting (ARC)
Swift использует ARC для управления памятью. Объект удаляется из памяти, когда на него больше нет ссылок.
🟠Наследование
В отличие от структур, классы могут наследовать свойства и методы от других классов. Поддерживают переопределение методов (
override).
🟠Идентичность объектов
Два объекта класса можно сравнивать по ссылке (===), а не только по значению (==).
class Animal {
var name: String
init(name: String) {
self.name = name
}
func speak() {
print("Some sound")
}
}
class Dog: Animal {
override func speak() {
print("Woof!")
}
}
let dog1 = Dog(name: "Buddy")
let dog2 = dog1 // Копируется ссылка, а не объект
dog2.name = "Charlie"
print(dog1.name) // "Charlie", так как dog1 и dog2 указывают на один объект
Ставь 👍 и забирай 📚 Базу знаний🤔 Как будешь исправлять краш на пришедшей строке?
Сначала нужно проверить формат данных и убедиться, что строка — валидна:
- использовать безопасное преобразование типов (if let, guard),
- обрабатывать nil,
- логировать ошибку и возвращать default-значение или показывать пользователю ошибку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Как работают 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)")
}
}
Ставь 👍 и забирай 📚 Базу знаний🤔 Какой самый яркий пример deadlock'а в iOS?
Классический deadlock
Если вызвать DispatchQueue.main.sync из UI-потока (main) — поток заблокируется сам на себе, вызывая мертвую блокировку. Такое случается при неправильной организации доступа к данным из UI.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Что относится к типам данных?
Это классификация различных видов данных, которые могут быть использованы и манипулированы в программе. Они определяют, какие операции можно выполнять с данными и как они хранятся в памяти.
🤔 Основные типы данных
🟠Примитивные типы данных
Представляют целые числа.
Int, UIn
let age: Int = 25
Представляют дробные числа. Float, Double
let pi: Double = 3.14159
Представляют логические значения true или false. Bool
let isActive: Bool = true
Представляют отдельные символы. Character
let letter: Character = "A"
🟠Составные типы данных (Composite data types)
Представляют последовательности символов. String
let greeting: String = "Hello, World!"
Представляют упорядоченные коллекции элементов одного типа. Array<T>
let numbers: [Int] = [1, 2, 3, 4, 5]
Представляют коллекции пар ключ-значение. Dictionary<Key, Value>
let user: [String: String] = ["name": "Alice", "age": "30"]
Представляют коллекции уникальных элементов. Set<T>
let uniqueNumbers: Set<Int> = [1, 2, 3, 4, 5]
🟠Пользовательские типы данных (User-defined data types)
Представляют тип данных с набором связанных значений. enum
enum CompassPoint {
case north
case south
case east
case west
}
Представляют группы связанных значений. struct
struct Person {
var name: String
var age: Int
}
let person = Person(name: "Alice", age: 30)
Представляют объекты с состоянием и поведением. class
class Car {
var model: String
var year: Int
init(model: String, year: Int) {
self.model = model
self.year = year
}
}
let car = Car(model: "Tesla", year: 2021)
🟠Специальные типы данных
Представляют группы нескольких значений различных типов. (Type1, Type2, ...)
let coordinates: (Int, Int) = (10, 20)
Представляют значение, которое может быть либо некоторым значением, либо nil. Optional<T>
var optionalName: String? = "Alice"
Ставь 👍 и забирай 📚 Базу знаний🤔 Какие типы CALayer есть?
Среди основных типов:
- CALayer — базовый слой.
- CAShapeLayer — для отрисовки векторной графики.
- CATextLayer — для отображения текста.
- CAGradientLayer — для градиентов.
- CAReplicatorLayer — для повторяющихся узоров.
- CATransformLayer — для 3D-трансформаций.
- CAEAGLLayer — для работы с OpenGL.
Каждый тип предоставляет свои возможности визуализации и анимации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Какие знаешь способы внедрения зависимостей?
Внедрение зависимостей (Dependency Injection, DI) в iOS-приложениях позволяет сделать код более модульным, тестируемым и поддерживаемым. Рассмотрим основные способы внедрения зависимостей в Swift.
🟠Внедрение через инициализатор (Initializer Injection)
Это самый распространенный и рекомендуемый способ. Зависимости передаются в объект через его инициализатор.
protocol NetworkServiceProtocol {
func fetchData()
}
class NetworkService: NetworkServiceProtocol {
func fetchData() {
print("Данные загружены")
}
}
// Класс, которому нужна зависимость
class ViewModel {
private let networkService: NetworkServiceProtocol
init(networkService: NetworkServiceProtocol) {
self.networkService = networkService
}
func loadData() {
networkService.fetchData()
}
}
// Использование
let networkService = NetworkService()
let viewModel = ViewModel(networkService: networkService)
viewModel.loadData()
🟠Внедрение через свойства (Property Injection)
Зависимость передается через свойство класса.
class ViewModel {
var networkService: NetworkServiceProtocol?
func loadData() {
networkService?.fetchData()
}
}
// Использование
let viewModel = ViewModel()
viewModel.networkService = NetworkService()
viewModel.loadData()
🟠Внедрение через метод (Method Injection)
Зависимость передается непосредственно в метод, который её использует.
class ViewModel {
func loadData(with networkService: NetworkServiceProtocol) {
networkService.fetchData()
}
}
// Использование
let viewModel = ViewModel()
let networkService = NetworkService()
viewModel.loadData(with: networkService)
🟠Использование Service Locator (Антипаттерн)
Класс сам запрашивает зависимость у глобального локатора.
class ServiceLocator {
static let shared = ServiceLocator()
private var services: [String: Any] = [:]
func register<T>(_ service: T) {
let key = String(describing: T.self)
services[key] = service
}
func resolve<T>() -> T? {
let key = String(describing: T.self)
return services[key] as? T
}
}
// Регистрация зависимостей
let locator = ServiceLocator.shared
locator.register(NetworkService() as NetworkServiceProtocol)
// Использование
class ViewModel {
func loadData() {
let networkService: NetworkServiceProtocol? = ServiceLocator.shared.resolve()
networkService?.fetchData()
}
}
🟠Использование DI-контейнеров (например, Swinject)
Специальные библиотеки помогают управлять зависимостями.
import Swinject
let container = Container()
container.register(NetworkServiceProtocol.self) { _ in NetworkService() }
class ViewModel {
private let networkService: NetworkServiceProtocol
init(networkService: NetworkServiceProtocol) {
self.networkService = networkService
}
func loadData() {
networkService.fetchData()
}
}
// Разрешение зависимости через контейнер
let networkService = container.resolve(NetworkServiceProtocol.self)!
let viewModel = ViewModel(networkService: networkService)
viewModel.loadData()
Ставь 👍 и забирай 📚 Базу знаний🤔 Что такое Pod?
Pod — это библиотека или фреймворк, подключаемый через CocoaPods, менеджер зависимостей в iOS. Он автоматически загружает, компилирует и подключает сторонние библиотеки к проекту.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Расскажи про букву D в solid
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит:
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
🚩Плохой пример (Нарушение DIP)
class MySQLDatabase {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class DataManager {
let database = MySQLDatabase() // Прямая зависимость от MySQL
func getData() -> String {
return database.fetchData()
}
}
🚩Хороший пример (Используем DIP)
Вводим абстракцию (Протокол)
protocol Database {
func fetchData() -> String
}
Реализуем конкретные базы данных
class MySQLDatabase: Database {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class PostgreSQLDatabase: Database {
func fetchData() -> String {
return "Данные из PostgreSQL"
}
}
Используем абстракцию в DataManager
class DataManager {
private let database: Database // Зависимость от абстракции
init(database: Database) {
self.database = database
}
func getData() -> String {
return database.fetchData()
}
}
Использование
let mySQLDataManager = DataManager(database: MySQLDatabase())
print(mySQLDataManager.getData()) // "Данные из MySQL"
let postgreSQLDataManager = DataManager(database: PostgreSQLDatabase())
print(postgreSQLDataManager.getData()) // "Данные из PostgreSQL"
Ставь 👍 и забирай 📚 Базу знаний🤔 Как ловил утечки памяти?
Для выявления утечек памяти используют инструмент Instruments, а именно его компонент Leaks, который помогает обнаружить утечки во время выполнения приложения. Важно избегать циклических ссылок, особенно при работе с замыканиями и объектами — для этого применяются слабые (weak) и несобственные (unowned) ссылки, что позволяет сборщику мусора корректно освобождать память. Анализ профилей памяти и использование метода deinit для проверки освобождения объектов также помогает обнаруживать утечки на ранних стадиях.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Что такое gitflow?
В основе Git Flow – несколько веток с разными ролями, чтобы команда могла параллельно разрабатывать новые фичи, исправлять баги и выпускать релизы.
🚩Как работает Git Flow?
🟠Основные ветки (`main` и `develop`)
-
main – содержит только стабильные версии.
- develop – основная ветка разработки, в неё вливаются все новые фичи.
🟠Разработка новых фич (feature branches)
- Каждая новая фича создаётся в отдельной ветке feature/*.
- После завершения сливается в develop.
git checkout develop
git checkout -b feature/new-cool-feature
# Разработка...
git checkout develop
git merge feature/new-cool-feature
git branch -d feature/new-cool-feature
🟠Подготовка к релизу (release branches)
- Когда код стабилен, создаётся ветка release/* от develop.
- Здесь можно тестировать и исправлять баги.
- После финального теста сливается в main и develop.
git checkout develop
git checkout -b release/1.0
# Фиксим баги, тестируем...
git checkout main
git merge release/1.0
git tag -a v1.0 -m "Release 1.0"
git checkout develop
git merge release/1.0
git branch -d release/1.0
🟠Горячие фиксы (hotfix branches)
- Если критический баг в main, создаём hotfix/*.
- После исправления вливаем в main и в develop.
git checkout main
git checkout -b hotfix/urgent-bugfix
# Фиксим баг...
git checkout main
git merge hotfix/urgent-bugfix
git checkout develop
git merge hotfix/urgent-bugfix
git branch -d hotfix/urgent-bugfix
Ставь 👍 и забирай 📚 Базу знаний🤔 Какие есть структуры данных?
1. Линейные: массивы, списки, стеки, очереди.
2. Нелинейные: деревья, графы.
3. Ассоциативные: хэш-таблицы, словари.
4. Специализированные: кучи, множества.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Какие плюсы и минусы 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.
Ставь 👍 и забирай 📚 Базу знаний
