В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций.
Когда один объект (например,
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
💊3
Синхронное соединение:
Преимущества:
- Простота реализации
- Последовательность выполнения
Недостатки:
- Блокирует поток
- Неэффективно при работе с сетью или ожиданием
Асинхронное соединение:
Преимущества:
- Не блокирует основной поток
- Позволяет обрабатывать несколько задач одновременно
Недостатки:
- Более сложная логика
- Труднее отлаживать и тестировать
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Свойства "Content Hugging Priority" и "Content Compression Resistance Priority" играют ключевую роль в системе Auto Layout. Эти свойства помогают определить, как вьюшки (views) должны быть отформатированы и как они реагируют на изменения в доступном пространстве в интерфейсе пользователя. Рассмотрим подробнее, что означает каждое из этих свойств и как они используются в разработке интерфейсов.
Определяет, насколько сильно вьюшка должна "обнимать" своё содержимое. Это свойство указывает на желательность вьюшки быть как можно ближе к своим внутренним размерам, основанным на своем содержимом.
Определяет, насколько сильно вьюшка должна противостоять сжатию размеров меньше, чем размеры её содержимого.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В iOS существует несколько ленивых (
lazy) контейнеров и вью, которые откладывают создание или загрузку элементов до момента их фактического использования. Обычное свойство инициализируется сразу, а
lazy – только при первом вызове. class Example {
lazy var expensiveObject: Data = {
print("Объект создан!")
return Data()
}()
}
let obj = Example()
print("Объект ещё не создан")
_ = obj.expensiveObject // Только теперь создастсяЕсли вы хотите избежать лишних вычислений, можно использовать ленивую последовательность:
let numbers = (1...1000).lazy.map { $0 * 2 } // Не вычисляется сразу!
print(numbers.first!) // Только теперь вычисляется первый элементВ отличие от обычных
VStack и HStack, ленивые версии создают элементы только при прокрутке.ScrollView {
LazyVStack {
ForEach(0..<1000) { index in
Text("Элемент \(index)")
}
}
}Они работают по принципу переиспользования ячеек, загружая их только когда нужно.
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
👍1
serial — вероятно, ошибка или сокращение. Возможно, имелся в виду SerialQueue (последовательная очередь).
Comparable — это протокол для сравнения объектов (<, >, ==), используется для сортировок и упорядочивания.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊13
Механизм Copy-on-Write (CoW) используется для оптимизации производительности и использования памяти при копировании объектов. Этот механизм особенно полезен для неизменяемых (immutable) структур данных. CoW часто ассоциируется со стандартными коллекциями и собственными типами данных, реализованными как структуры (value types), такие как
Array, String, Dictionary, и Set.Работает так, что копия объекта создаётся только в тот момент, когда происходит попытка модификации. До этого момента все копии объекта фактически ссылаются на одни и те же данные в памяти. Это позволяет сэкономить как время, так и память, поскольку избегается ненужное дублирование данных, когда оно не требуется.
Автоматически применяет механизм CoW к своим стандартным коллекциям, таким как
Array, String, Dictionary, и Set. Это означает, что при передаче этих объектов в функции или при их копировании реальное дублирование данных происходит только в случае модификации одной из копий. Таким образом, если вы создаёте копию массива и не изменяете его, обе переменные будут указывать на одни и те же данные в памяти. Как только вы модифицируете одну из копий, Swift создаст реальную копию данных для этой копии, обеспечивая независимость данных между оригиналом и копией.var originalArray = [1, 2, 3]
var copiedArray = originalArray // На этом этапе данные не дублируются
copiedArray.append(4) // Теперь данные копируются, потому что copiedArray модифицируется
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Это механизм динамического диспетчинга в Swift, используемый для работы с протоколами.
- Если структура или класс реализуют протокол, Swift создает Witness Table, хранящую указатели на методы.
- Это позволяет динамически вызывать методы, объявленные в протоколе, даже если тип не известен во время компиляции.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift есть несколько инструментов для работы с многопоточностью и параллельным выполнением кода. Вот основные из них:
GCD – это низкоуровневая технология, позволяющая управлять задачами (тасками) в очередях (
DispatchQueue). DispatchQueue.global(qos: .background).async {
print("Фоновый поток")
DispatchQueue.main.async {
print("Вернулись в главный поток")
}
}OperationQueue – это более гибкая и объектно-ориентированная альтернатива GCD.
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2 // Ограничение на 2 задачи одновременно
queue.addOperation {
print("Операция 1")
}
queue.addOperation {
print("Операция 2")
}
С
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()) // Потокобезопасный доступ
}С
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
- HEAD — как GET, но без тела. Используется, чтобы узнать метаинформацию (например, размер файла или заголовки) без загрузки содержимого.
- GET — запрашивает данные с сервера. Не изменяет состояние сервера.
- POST — отправляет данные на сервер для создания нового ресурса. Неидемпотентен.
- PUT — отправляет данные для полного обновления существующего ресурса. Идемпотентен.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Структуры (
struct) – это один из основных типов данных в Swift. Они значимые (value type), то есть при передаче копируются, а не передаются по ссылке. Value type – при передаче копируется (в отличие от классов)
Нет ARC (автоматического подсчета ссылок) – производительность выше
Могут иметь методы, свойства, инициализаторы
Работают с протоколами (protocol-oriented programming)
Не поддерживают наследование
struct Car {
var model: String
var year: Int
func description() -> String {
return "\(model) – \(year)"
}
}
let car1 = Car(model: "Tesla", year: 2023)
var car2 = car1 // Создается копия
print(car1.description()) // Tesla – 2023
print(car2.description()) // Tesla – 2023
car2.year = 2024 // Изменяем car2, но car1 остается прежним
print(car1.year) // 2023
print(car2.year) // 2024По умолчанию методы не могут изменять свойства структуры. Чтобы изменить их внутри метода, нужно использовать
mutatingstruct Counter {
var count = 0
mutating func increment() {
count += 1
}
}
var counter = Counter()
counter.increment()
print(counter.count) // 1Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM