Task priority — это указание уровня важности задачи, которое система может учитывать при распределении ресурсов. Приоритет не гарантирует порядок, но даёт подсказку планировщику, какие задачи предпочтительнее обрабатывать первыми. В Swift есть уровни приоритетов (например, high, low, utility и другие).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Утечка памяти (
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) ссылки не увеличивают счётчик ссылок, что разрывает цикл.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 похож на 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 удалён"Замыкания захватывают объекты, создавая циклические ссылки.
Проблема:
self удерживается замыканиемclass ViewController {
var closure: (() -> Void)?
func setup() {
closure = {
print(self) // Удерживает self, создавая цикл!
}
}
deinit { print("ViewController удалён") }
}
var vc: ViewController? = ViewController()
vc?.setup()
vc = nil // ❌ "ViewController" НЕ удалится- Открываем
Xcode > Product > Profile. - Выбираем
Leaks. - Запускаем приложение и проверяем, остаются ли объекты в памяти.
Если метод
deinit не вызывается – значит, объект утёк в память.class Test {
deinit { print("Test удалён") }
}
var obj: Test? = Test()
obj = nil // Должно напечатать "Test удалён"- В Xcode открываем "Debug Memory Graph" (нажимая значок в Debugger).
- Смотрим, какие объекты остались в памяти.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Ключ должен соответствовать протоколу Hashable. Это необходимо, чтобы можно было быстро сравнивать и размещать ключи в хэш-таблице словаря.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
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
👍5
В SwiftUI или Jetpack Compose composition full layout означает создание интерфейса из переиспользуемых, независимых компонентов. Он строится через композицию небольших вью или функций, каждая из которых отвечает за отдельную часть интерфейса, что повышает читаемость и тестируемость.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
Протокол (интерфейс) описывает поведение, а при подключении к нему класс или структура обязываются реализовать методы, тем самым приобретая определённое поведение. Это форма абстракции и инверсии управления.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift ссылки (references) на объекты могут быть сильными (strong) и слабыми (weak). Они отличаются способом управления памятью и временем жизни объектов, на которые ссылаются.
Сильная ссылка (strong reference) удерживает объект в памяти. Пока существует хотя бы одна сильная ссылка на объект, он не будет удалён из памяти.
Сильные ссылки используются по умолчанию и обеспечивают, что объект остаётся доступным до тех пор, пока он необходим.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
var person1: Person? = Person(name: "Alice")
var person2: Person? = person1 // person2 имеет сильную ссылку на тот же объект, что и person1
person1 = nil // Объект все еще удерживается в памяти благодаря person2
print(person2?.name) // Output: Alice
person2 = nil // Теперь объект будет удалён из памяти, так как нет сильных ссылокСлабая ссылка (weak reference) не удерживает объект в памяти. Если объект больше не имеет сильных ссылок, он будет удалён из памяти, даже если на него существуют слабые ссылки.
Слабые ссылки используются для предотвращения циклических ссылок, которые могут привести к утечкам памяти.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
class Apartment {
var tenant: Person?
init(tenant: Person?) {
self.tenant = tenant
}
}
var alice: Person? = Person(name: "Alice")
var apartment: Apartment? = Apartment(tenant: alice)
// Создание слабой ссылки для предотвращения циклической зависимости
class Tenant {
var name: String
weak var apartment: Apartment? // Слабая ссылка
init(name: String) {
self.name = name
}
}
let tenant = Tenant(name: "Bob")
apartment?.tenant = alice
alice = nil // Объект Person будет удалён из памяти, так как больше нет сильных ссылок
print(apartment?.tenant?.name) // Output: nilСильные ссылки: Удерживают объект в памяти. Объект будет освобождён только тогда, когда все сильные ссылки на него будут удалены.
Слабые ссылки: Не удерживают объект в памяти. Объект будет освобождён, когда не останется сильных ссылок.
Сильные ссылки: Используются по умолчанию для обеспечения сохранности объектов в памяти.
Слабые ссылки: Используются для предотвращения циклических ссылок и утечек памяти, особенно в структурах данных с взаимосвязанными объектами.
Сильные ссылки: Не обнуляются автоматически при удалении объекта из памяти.
Слабые ссылки: Автоматически обнуляются, когда объект, на который они ссылаются, удаляется из памяти.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
Чтобы создать вью с нестандартной формой, нужно:
1. Переопределить метод draw(_:) в кастомном UIView.
2. Использовать API Core Graphics, например UIBezierPath, CGContext.
3. Для маски или формы — можно задать layer.mask или использовать CAShapeLayer.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
RunLoop — это фундаментальный механизм в iOS и macOS, который управляет циклом обработки событий в приложении. Он отслеживает и обрабатывает входящие события, такие как нажатия клавиш, касания экрана, таймеры и сетевые запросы, и поддерживает приложение в активном состоянии, пока оно не завершится.RunLoop постоянно выполняет цикл, ожидая входящие события и обрабатывая их по мере поступления. Этот цикл состоит из нескольких этапов: ожидание события, обработка события и повтор цикла.RunLoop может работать в разных режимах, которые определяют, какие источники событий будут отслеживаться и обрабатываться. Основные режимы включают default и tracking (для событий отслеживания, таких как прокрутка). В каждой итерации RunLoop обрабатывает события только для текущего режима.RunLoop.current.run(mode: .default, before: Date.distantFuture)
RunLoop может отслеживать различные источники событий, такие как таймеры (Timer), порты (Port), ввод пользователей (такие как касания экрана и клики мыши), а также пользовательские источники (Input Source).RunLoop может управлять таймерами, которые выполняют задачи через определенные интервалы времени. let timer = Timer(timeInterval: 1.0, repeats: true) { _ in
print("Timer fired!")
}
RunLoop.current.add(timer, forMode: .default)RunLoop используется для обработки событий в основном потоке (main thread) приложения. Это особенно важно для поддержания отзывчивости пользовательского интерфейса, поскольку все взаимодействия с UI происходят в основном потоке.import Foundation
class Example {
var timer: Timer?
func startRunLoop() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
RunLoop.current.run()
}
@objc func timerFired() {
print("Timer fired!")
}
}
let example = Example()
example.startRunLoop()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- Использовать NSCache с автоматическим удалением;
- Хранить изображения по UUID или hash;
- Проверять размер файла, тип данных;
- Очищать кэш при нехватке памяти (didReceiveMemoryWarning);
- Удалять устаревшие записи по дате.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Если оставить контекст в замыкании, не принимая во внимание возможные проблемы, это может привести к нескольким серьезным проблемам, особенно в многопоточном и асинхронном программировании.
Одной из самых распространенных проблем является утечка памяти из-за циклов удержания (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()Когда замыкания захватывают изменяемый контекст, это может привести к условиям гонки и непредсказуемому поведению, особенно при работе в многопоточном окружении. Если метод
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
Фреймы логично использовать в анимациях, при рисовании на Canvas, и в простых элементах интерфейса, где точное позиционирование важнее гибкости. Также актуальны при создании кастомных вью или в играх.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Apple предпочитает value types (структуры
struct) по умолчанию в Swift по нескольким причинамstruct копируется при передаче, а не передается по ссылке, как class. Это снижает вероятность гонки данных (data race), когда один поток изменяет объект, а другой читает его одновременно.
В многопоточной среде это делает код более безопасным.
struct Point {
var x: Int
var y: Int
}
var p1 = Point(x: 1, y: 2)
var p2 = p1 // p2 - это копия, изменения в p2 не затронут p1
p2.x = 10
print(p1.x) // 1
print(p2.x) // 10struct хранятся в стеке, а не в куче, что делает их создание и удаление быстрее. Куча (
heap) требует управления памятью (ARC – Automatic Reference Counting), а struct — нет. class MyClass { var value = 0 } // В куче (heap), управляется ARC
struct MyStruct { var value = 0 } // В стеке (stack), копируется при передачеstruct ведут себя как примитивные типы (Int, Double), что делает код предсказуемым. Их изменение происходит локально, без неожиданных эффектов в других частях программы.
class Car {
var speed: Int
init(speed: Int) { self.speed = speed }
}
var car1 = Car(speed: 60)
var car2 = car1 // car2 - это ссылка на тот же объект
car2.speed = 100 // Изменение затрагивает car1!
print(car1.speed) // 100 (хотя мы меняли car2!)Swift изначально построен на
struct: Int, Double, Bool, Array, Dictionary, String — это структуры. Это делает язык более безопасным и производительным.
var arr1 = [1, 2, 3]
var arr2 = arr1 // Копия массива, а не ссылка!
arr2.append(4)
print(arr1) // [1, 2, 3] (не изменился!)
print(arr2) // [1, 2, 3, 4] (новый массив)
Хотя
struct — предпочтительный выбор, class нужен, когда: Нужна ссылочная семантика (например, объект должен изменяться в разных местах кода).
Есть сложные иерархии наследования.
Требуется работа с Objective-C (
NSObject).Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3
Словарь (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"]Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- Auto Layout (наиболее гибкий и универсальный).
- Stack Views (удобные группы элементов с автоматической раскладкой).
- Frame-based layout (устаревший способ вручную).
- Constraint anchors и визуальный язык разметки (VFL).
- Interface Builder (через Xcode UI).
- SwiftUI (декларативный подход).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
👍1🔥1
Классы передаются по ссылке, а структуры по значению.
- К объектам класса обращаются через ссылку (let obj = MyClass()), изменения в одной переменной отразятся на всех экземплярах.
- К объектам структуры обращаются как к копиям, каждое присваивание создает новый объект (let obj = MyStruct()).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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