и посмотреть медиа
Preguntas de entrevista de Swift
и посмотреть медиа
Preguntas, pruebas y tareas para desarrolladores de iOS en Telegram.
Preguntas, pruebas y tareas para desarrolladores de iOS en Telegram.
bot de IA para clonar texto a voz y voz en Telegram. Cree audio utilizando la red neuronal de forma rápida y fácil.
El canal está dedicado a la preparación de entrevistas en idioma Swift. Contiene preguntas actuales, pruebas, tareas prácticas e información de vacantes. Ideal para desarrolladores iOS principiantes y experimentados que quieren refrescar sus conocimientos y pasar con éxito entrevistas.
🤔 Что происходит с классом при компиляции? При компиляции в Swift класс проходит несколько стадий обработки: Анализ синтаксиса и семантики – компилятор проверяет код на ошибки. Генерация промежуточного представления (IR) – создаётся код на уровне LLVM IR. Оптимизация – Swift применяет различные оптимизации, например, inlining, dead code elimination и другие. Генерация машинного кода – итоговый код превращается в исполняемый машинный код, специфичный для платформы. 🚩Что конкретно происходит с классом? В отличие от структур, классы в Swift являются ссылочными типами и хранятся в куче (heap). Это означает, что: - При создании объекта выделяется память в куче. - Swift автоматически использует ARC (Automatic Reference Counting) для управления памятью. - Методы класса могут вызываться через виртуальную таблицу (vtable), если класс использует динамическую диспетчеризацию. 🚩Важные моменты - Если класс final, компилятор может оптимизировать вызовы методов, убрав динамическую диспетчеризацию. - Наследование делает вызовы методов менее предсказуемыми (они идут через vtable). - В отличие от структур, классы не копируются при передаче в функцию, а передаётся ссылка. class Animal { var name: String init(name: String) { self.name = name } func speak() { print("Some sound") } } final class Dog: Animal { override func speak() { print("Woof!") } } let myDog = Dog(name: "Buddy") myDog.speak() Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Какие есть инструменты для работы с потоками? В 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) } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что нужно сделать, чтобы кастомная структура стала ключом в dictionary? В Swift ключи в словаре (Dictionary) должны быть уникальными и сравниваться между собой. Поэтому, если вы хотите использовать*свою структуру в качестве ключа, она должна соответствовать протоколу Hashable. 🚩Что нужно? Структура должна соответствовать Hashable Должен быть реализован hash(into:) или использовать Equatable + Hashable автоматически Свойства структуры должны быть Hashable (если String, Int, Double – все ок) 🚩Пример кастомной структуры в `Dictionary` struct Person: Hashable { let id: Int let name: String } // Теперь можно использовать `Person` как ключ var peopleAges: [Person: Int] = [ Person(id: 1, name: "Alice"): 25, Person(id: 2, name: "Bob"): 30 ] // Доступ по ключу let alice = Person(id: 1, name: "Alice") print(peopleAges[alice] ?? "Не найдено") // 25 🚩Ручная реализация `hash(into:)` Если нужно кастомное хеширование, можно реализовать hash(into:): struct Person: Hashable { let id: Int let name: String func hash(into hasher: inout Hasher) { hasher.combine(id) // Используем только id для хеша } } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Как устроено наследование? Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её. 🚩Основы наследования 🟠Определение базового класса Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами. 🟠Создание подкласса Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие. 🟠Переопределение методов и свойств Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения. 🟠Предотвращение переопределения Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова 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. Это позволяет подклассам расширять, а не заменять поведение суперкласса. Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Как остановить подписку, когда пользователь не видит экран? Подписку следует удалить в момент, когда экран становится невидимым: - В UIKit: viewWillDisappear или viewDidDisappear. - В SwiftUI: onDisappear. Также важно: - Для Combine использовать AnyCancellable и занулять его (cancellable = nil). - В RxSwift — использовать disposeBag или вручную вызывать dispose(). Это предотвращает утечки памяти и ненужную работу подписки в фоне. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Чем опасна утечка памяти? Утечка памяти (memory leak) – это ситуация, когда память остаётся выделенной, но больше не используется программой и не освобождается. class Person { var pet: Pet? deinit { print("Person удалён") } } class Pet { var owner: Person? deinit { print("Pet удалён") } } var person: Person? = Person() var pet: Pet? = Pet() person?.pet = pet pet?.owner = person person = nil pet = nil 🚩Как избежать утечек памяти? 🟠Использовать `weak` или `unowned` ссылки Слабые (weak) или безвладельческие (unowned) ссылки не увеличивают счётчик ссылок, что разрывает цикл. class Person { var pet: Pet? deinit { print("Person удалён") } } class Pet { weak var owner: Person? // Слабая ссылка deinit { print("Pet удалён") } } var person: Person? = Person() var pet: Pet? = Pet() person?.pet = pet pet?.owner = person person = nil // "Person удалён" pet = nil // "Pet удалён" 🟠Использовать `unowned`, если объект всегда будет существовать unowned похож на weak, но он не может быть `nil`. class Owner { var car: Car? deinit { print("Owner удалён") } } class Car { unowned var owner: Owner // Безвладельческая ссылка init(owner: Owner) { self.owner = owner } deinit { print("Car удалён") } } var owner: Owner? = Owner() owner?.car = Car(owner: owner!) owner = nil // "Owner удалён", "Car удалён" 🟠Разрывать циклы в замыканиях (`[weak self]`) Замыкания захватывают объекты, создавая циклические ссылки. Проблема: self удерживается замыканием class ViewController { var closure: (() -> Void)? func setup() { closure = { print(self) // Удерживает self, создавая цикл! } } deinit { print("ViewController удалён") } } var vc: ViewController? = ViewController() vc?.setup() vc = nil // ❌ "ViewController" НЕ удалится 🚩Как найти утечки памяти? 🟠Использовать `Instrument – Leaks` в Xcode - Открываем Xcode > Product > Profile. - Выбираем Leaks. - Запускаем приложение и проверяем, остаются ли объекты в памяти. 🟠Проверить `deinit` Если метод deinit не вызывается – значит, объект утёк в память. class Test { deinit { print("Test удалён") } } var obj: Test? = Test() obj = nil // Должно напечатать "Test удалён" 🟠Включить `Malloc Stack Logging` - В Xcode открываем "Debug Memory Graph" (нажимая значок в Debugger). - Смотрим, какие объекты остались в памяти. Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 В чем проблема, если все переменные будут делаться в вик? Если все переменные в коде сделать weak, объекты могут мгновенно удаляться из памяти, потому что никто не будет владеть ими (strong reference). 🚩Как работает `weak`? - weak создает слабую ссылку – объект не увеличивает счетчик ссылок (retain count). - Если нет других (strong) ссылок на объект, он удаляется (ARC освобождает память). - weak переменные всегда являются Optional, потому что объект может стать nil в любой момент. class Person { weak var name: String? // ❌ Ошибка! Строки – это value type, weak нельзя } Проблема, если weak используется везде class Car { weak var model: String? // ❌ Ошибка (value type) weak var owner: Person? // ⚠️ Будет nil, если нет других strong ссылок } class Person { var car: Car? } var person: Person? = Person() person?.car = Car() person?.car?.owner = person // ❌ `owner` - weak, объект сразу удалится print(person?.car?.owner) // nil, объект Person уничтожен 🚩Когда `weak` полезен? 🟠Избегание циклов ссылок (retain cycle) Например, между delegate и ViewController protocol SomeDelegate: AnyObject { func doSomething() } class ViewController { weak var delegate: SomeDelegate? // ✅ Prevent retain cycle } 🟠Когда объект не должен владеть другим объектом Например, ячейки в UITableView не должны владеть ViewController. Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что будет, если открыть несколько экранов и сделать dismiss последнего? Когда вы открываете несколько экранов (UIViewController) в iOS, они обычно создают стек представлений (View Controller Stack). В зависимости от способа открытия экранов (модально или через навигационный стек), поведение dismiss будет разным. 🚩Модальное представление (`present`) Если экраны открывались модально (present), то dismiss на последнем экране просто закроет только этот экран, и управление вернётся к предыдущему. let newVC = UIViewController() present(newVC, animated: true) Позже вызываем: dismiss(animated: true) Если вызвать dismiss на первом модально представленном контроллере, все последующие модальные контроллеры закроются сразу. // Открываем два экрана последовательно let vc1 = UIViewController() let vc2 = UIViewController() present(vc1, animated: true) vc1.present(vc2, animated: true) Если вызвать dismiss на vc2: vc2.dismiss(animated: true) Если вызвать dismiss на vc1: vc1.dismiss(animated: true) 🚩Навигационный стек (`push`) Если экраны открывались через UINavigationController (pushViewController), то dismiss не работает для удаления последнего экрана. Нужно использовать popViewController. let vc1 = UIViewController() let vc2 = UIViewController() navigationController?.pushViewController(vc1, animated: true) navigationController?.pushViewController(vc2, animated: true) Теперь если мы вызовем: vc2.dismiss(animated: true) Правильный способ закрытия последнего экрана в UINavigationController: navigationController?.popViewController(animated: true) Если вы хотите закрыть весь стек экранов, используйте: navigationController?.popToRootViewController(animated: true) Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Перечислите все ленивые (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.. UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = "Строка \(indexPath.row)" return cell } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиаSolo los usuarios registrados pueden compartir su opinión.
¡Sé el primero en compartir tu experiencia con este recurso!