UserDefaults — это хранилище для сохранения простых данных (строки, числа, массивы). Но если нужно сохранить сложные объекты, их сначала кодируют в `Data` (Codable), а затем сохраняют. Для примитивных типов (строки, числа, массивы, словари)
UserDefaults работает без кодирования:let defaults = UserDefaults.standard
// Сохранение
defaults.set("Иван", forKey: "username")
defaults.set(25, forKey: "age")
// Чтение
let name = defaults.string(forKey: "username") ?? "Нет имени"
let age = defaults.integer(forKey: "age")
print(name, age) // Иван 25
Если нужно сохранить свой объект, сначала его нужно закодировать в
Data.struct User: Codable {
let name: String
let age: Int
}Сохранение в
UserDefaultslet user = User(name: "Иван", age: 25)
let defaults = UserDefaults.standard
if let encoded = try? JSONEncoder().encode(user) {
defaults.set(encoded, forKey: "user")
}
Загрузка из
UserDefaultsif let savedData = defaults.data(forKey: "user"),
let savedUser = try? JSONDecoder().decode(User.self, from: savedData) {
print(savedUser.name, savedUser.age) // Иван 25
}
Чтобы удалить ключ:
defaults.removeObject(forKey: "user")
Можно сохранить массив объектов, просто закодировав его:
let users = [
User(name: "Иван", age: 25),
User(name: "Анна", age: 30)
]
if let encoded = try? JSONEncoder().encode(users) {
defaults.set(encoded, forKey: "users")
}
// Читаем массив обратно
if let savedData = defaults.data(forKey: "users"),
let savedUsers = try? JSONDecoder().decode([User].self, from: savedData) {
print(savedUsers) // [{name: Иван, age: 25}, {name: Анна, age: 30}]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Fetched Property — это динамическая связь, основанная на предопределённом запросе (fetch request). В отличие от обычных связей (relationship), она:
- не кешируется;
- выполняет отдельный запрос каждый раз при доступе;
- может фильтровать или выбирать связанные объекты по более сложным правилам.
Это полезно в случаях, когда нужно получить связанные данные по определённым условиям, но нужно учитывать, что производительность ниже, чем у обычной связи.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В
Operation (ранее NSOperation) в Foundation есть встроенный механизм отмены, который позволяет корректно завершить операцию, если она больше не нужна. Однако отмена не прерывает выполнение автоматически – код внутри операции должен сам проверять флаг отмены и корректно завершаться. Вызывается
cancel() – операция помечается как отмененная. Флаг
isCancelled становится true, но операция продолжает выполняться, если не проверяет этот флаг. Операция должна самостоятельно проверять
isCancelled и прерываться. class MyOperation: Operation {
override func main() {
for i in 1...10 {
if isCancelled { return } // Проверяем, отменена ли операция
print("Выполняется шаг \(i)")
sleep(1) // Симуляция работы
}
}
}
let queue = OperationQueue()
let operation = MyOperation()
queue.addOperation(operation)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
operation.cancel() // Отменяем через 3 секунды
}Если операция асинхронная (
isAsynchronous = true), просто проверять isCancelled недостаточно. Надо корректно управлять состояниями (isExecuting, isFinished).class AsyncOperation: Operation {
private var _executing = false
private var _finished = false
override var isAsynchronous: Bool { true }
override var isExecuting: Bool {
get { return _executing }
set {
willChangeValue(for: \.isExecuting)
_executing = newValue
didChangeValue(for: \.isExecuting)
}
}
override var isFinished: Bool {
get { return _finished }
set {
willChangeValue(for: \.isFinished)
_finished = newValue
didChangeValue(for: \.isFinished)
}
}
override func start() {
if isCancelled {
isFinished = true
return
}
isExecuting = true
executeTask()
}
private func executeTask() {
DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
if self.isCancelled {
self.complete()
return
}
print("Асинхронная операция завершена")
self.complete()
}
}
private func complete() {
isExecuting = false
isFinished = true
}
}
let queue = OperationQueue()
let asyncOp = AsyncOperation()
queue.addOperation(asyncOp)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
asyncOp.cancel() // Отменяем через 1 секунду
}Если у вас есть зависимости между операциями, отмена одной может автоматически отменить все последующие:
let op1 = MyOperation()
let op2 = MyOperation()
op2.addDependency(op1)
let queue = OperationQueue()
queue.addOperations([op1, op2], waitUntilFinished: false)
// Отменяем первую операцию, вторая тоже не выполнится
op1.cancel()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
При компиляции в 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()Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Apple рекомендует использовать значимые типы (например, struct, enum) по следующим причинам:
- Они более предсказуемы, потому что копируются при передаче, и изменения в одной копии не затрагивают другие.
- Это упрощает многопоточность и предотвращает гонки данных.
- Swift делает копирование структур эффективным благодаря Copy-On-Write.
- Для UI и моделей данных это снижает количество неожиданных побочных эффектов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её.
Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами.
Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие.
Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения.
Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова
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. Это позволяет подклассам расширять, а не заменять поведение суперкласса.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Регулярное участие в собеседованиях (раз в полгода-год) помогает:
- держать навыки общения в тонусе;
- понимать ожидания рынка;
- адекватно оценивать свою стоимость;
- быть готовым к внезапным изменениям в работе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6
В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций.
Когда один объект (например,
ViewController) зависит от другого (NetworkManager), первый становится клиентом, а второй – зависимостью. class NetworkManager {
func fetchData() {
print("Данные загружены")
}
}
class ViewController {
let networkManager: NetworkManager
init(networkManager: NetworkManager) {
self.networkManager = networkManager
}
func loadData() {
networkManager.fetchData()
}
}Жесткие зависимости можно ослабить, используя протоколы.
protocol NetworkService {
func fetchData()
}
class NetworkManager: NetworkService {
func fetchData() {
print("Данные загружены")
}
}
class ViewController {
let networkService: NetworkService
init(networkService: NetworkService) {
self.networkService = networkService
}
func loadData() {
networkService.fetchData()
}
}В MVVM зависимость между
ViewController и ViewModel. В VIPER модули зависят друг от друга, но слабо связаны через протоколы.
В DI (Dependency Injection) зависимости передаются снаружи, что повышает тестируемость и гибкость.
Чтобы управлять внешними зависимостями (библиотеками), используются
Swift Package Manager (SPM)
CocoaPods
Carthage
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS для выполнения фоновых задач существуют несколько ключевых механизмов:
DispatchQueue.global(qos: .background).async {
// Фоновая задача
}let queue = OperationQueue()
queue.addOperation {
// Фоновая операция
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Фоновое обновление данных
completionHandler(.newData)
} import BackgroundTasks
func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.app.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
try? BGTaskScheduler.shared.submit(request)
}
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app.background")
let session = URLSession(configuration: configuration)
let url = URL(string: "https://example.com/largefile")!
let task = session.downloadTask(with: url)
task.resume()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Подсчёт ссылок работает во время исполнения программы, в момент изменения количества strong-ссылок. Увеличивается при присваивании, уменьшается при обнулении или выходе из области видимости.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Объектно-ориентированное программирование (ООП) — это парадигма, основанная на концепции "объектов", которые могут содержать данные в виде полей (часто называемых атрибутами или свойствами) и код в виде процедур (часто называемых методами). ООП фокусируется на использовании объектов для моделирования реального мира (или абстракций), облегчая разработку и поддержку сложных программ. Существует четыре основных принципа:
Механизм ООП, который объединяет данные (атрибуты) и код (методы), манипулирующий этими данными, внутри одного объекта и скрывает детали реализации от внешнего использования. Это позволяет защитить внутреннее состояние объекта от прямого доступа извне и обеспечить контролируемый интерфейс для работы с этим объектом.
Позволяет создавать новый класс на основе уже существующего класса, перенимая его свойства и методы. Новый класс может добавлять собственные свойства и методы или модифицировать унаследованные. Наследование обеспечивает повторное использование кода, упрощает его расширение и поддержку.
Способность объектов с одинаковым интерфейсом предоставлять различную реализацию для одного и того же метода. Это означает, что функция или метод могут использоваться для различных типов объектов, и каждый тип может реализовать эту функцию или метод по-своему. Полиморфизм упрощает написание общего кода для работы с объектами разных классов и обеспечивает гибкость в его использовании.
Позволяет скрыть сложность системы, представляя её ключевые аспекты и скрывая детали реализации. Это достигается за счёт использования абстрактных классов и интерфейсов, которые определяют шаблон для классов-наследников. Абстракция помогает сосредоточиться на взаимодействии объектов на более высоком уровне, игнорируя ненужные детали.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит:
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
class MySQLDatabase {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class DataManager {
let database = MySQLDatabase() // Прямая зависимость от MySQL
func getData() -> String {
return database.fetchData()
}
}Вводим абстракцию (Протокол)
protocol Database {
func fetchData() -> String
}Реализуем конкретные базы данных
class MySQLDatabase: Database {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class PostgreSQLDatabase: Database {
func fetchData() -> String {
return "Данные из PostgreSQL"
}
}Используем абстракцию в
DataManagerclass 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"
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Garbage Collector (GC) и Automatic Reference Counting (ARC) – это два разных подхода к управлению памятью в программировании. Они решают одну задачу: автоматическое освобождение неиспользуемой памяти, но делают это по-разному.
Java, Kotlin, C#, Python, JavaScript
- GC периодически просматривает всю память приложения и ищет объекты, на которые больше нет ссылок.
- Когда такие объекты находятся, они удаляются, а память освобождается.
- Это автоматический процесс, который запускается по мере необходимости.
Где используется: Swift, Objective-C
- Каждый объект имеет счетчик ссылок (
reference count). - Когда переменная создает ссылку на объект, счетчик увеличивается.
- Когда переменная перестает ссылаться на объект, счетчик уменьшается.
- Когда счетчик достигает нуля, объект удаляется из памяти сразу же.
class Person {
var pet: Pet?
}
class Pet {
var owner: Person?
}
let person = Person()
let pet = Pet()
person.pet = pet
pet.owner = person // Теперь оба объекта держат друг друга, и ARC их не удалитРешение – использовать
weak: class Pet {
weak var owner: Person? // Теперь утечки памяти не будет
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Да, если хочешь сохранить или передать её как Codable, Hashable, Equatable и т.д. Протоколы обеспечивают интерфейс и поддержку функционала на уровне абстракции.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
@autoclosure — это специальный атрибут в Swift, который автоматически превращает переданное выражение в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится. @autoclosure?Обычно его используют для улучшения читаемости кода, особенно когда нужно лениво вычислять аргумент функции. Например, если переданный аргумент — это сложное вычисление, его выполнение можно отложить до нужного момента.
Допустим, у нас есть функция, которая принимает замыкание
func logMessage(_ message: () -> String) {
print("Лог: \(message())")
}
// Вызываем функцию, передавая замыкание
logMessage { "Сообщение: \(2 + 2)" }
Теперь используем `@autoc чтобы сделать вызов функции проще
func logMessage(_ message: @autoclosure () -> String) {
print("Лог: \(message())")
}
// Теперь аргумент можно передавать без {}
logMessage("Сообщение: \(2 + 2)")
Стандартные функции Swift используют @autoclosure, чтобы избежать вычисления аргументов, если проверка не нужна:assert(2 + 2 == 4, "Ошибка: 2 + 2 не равно 4!")
Допустим, у нас есть функция, которая выполняет блок только если включен режим отладкие в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится.
Обычно его используют для улучшения читаемости кода, особенно когда нужно.`@autoc но если нужно сохранить замыкание для будущего выполнения, это можно сделать рый автоматически превращает переданное выражение в замыкание. Это позволяет отложить выполнение выражения до момента, когда оно действительно понадобится.
Обычно его используют для улучшения читаемости кода, особенно когда нужно лениво вычислять аргумент функции.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2
Синхронное соединение:
Преимущества:
- Простота реализации
- Последовательность выполнения
Недостатки:
- Блокирует поток
- Неэффективно при работе с сетью или ожиданием
Асинхронное соединение:
Преимущества:
- Не блокирует основной поток
- Позволяет обрабатывать несколько задач одновременно
Недостатки:
- Более сложная логика
- Труднее отлаживать и тестировать
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM