В iOS жизненный цикл
UIViewController определяет последовательность вызовов методов, происходящих во время создания, отображения, скрытия и уничтожения контроллера. На этом этапе создаётся экземпляр
UIViewController, но его view ещё не загружено. - Можно переопределить
init() или init(coder:), если контроллер создаётся из Storyboard. - Можно передавать данные через инициализатор.
class MyViewController: UIViewController {
var titleText: String
init(titleText: String) {
self.titleText = titleText
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}Когда контроллеру нужно отобразить свой
view, вызывается loadView() (если представление создаётся программно) и viewDidLoad() (если загружается из Storyboard или XIB). loadView() – создаёт view программно (обычно не переопределяется). viewDidLoad() – вызывается один раз после загрузки view. override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
print("viewDidLoad - View загружено в память")
}Когда
UIViewController добавляется в иерархию UIWindow и становится видимым, вызываются следующие методы: viewWillAppear(_:) – вызывается перед появлением на экране. viewDidAppear(_:) – вызывается после появления на экране. viewWillDisappear(_:) – вызывается перед скрытием. viewDidDisappear(_:) – вызывается после скрытия. override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear - View скоро появится на экране")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear - View уже на экране")
}Когда
UIViewController больше не нужен, вызывается deinit(), а его view может быть выгружено с вызовом viewDidUnload() (но сейчас это редко используется). deinit {
print("deinit - Контроллер удалён из памяти")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Это механизм публикации и подписки на события в iOS.
- Позволяет компонентам приложения обмениваться данными без прямых ссылок.
- Работает по принципу наблюдателя: объект отправляет уведомление, а подписчики получают его.
- Используется для глобального взаимодействия между модулями (например, обновление UI после фоновой загрузки данных).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это сообщения, которые отправляются приложением пользователю даже тогда, когда само приложение не активно. Это эффективный способ удержания пользователей и предоставления им важной информации.
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения push-уведомлений. Для этого приложение отправляет запрос к Apple Push Notification Service (APNs) с запросом на получение уникального токена устройства (device token).
APNs генерирует уникальный токен для устройства и отправляет его обратно приложению. Приложение затем передает этот токен на свой сервер.
Когда необходимо отправить push-уведомление, сервер приложения формирует сообщение, включающее содержимое уведомления и токен устройства, и отправляет его на APNs.
APNs принимает сообщение от сервера, определяет устройство по токену и отправляет уведомление на это устройство.
Когда устройство получает уведомление, операционная система отображает его пользователю. Если пользователь взаимодействует с уведомлением, приложение может выполнить определенные действия, такие как открытие конкретного экрана.
В 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)")
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Set хранит уникальные элементы без порядка, а Dictionary — пары ключ-значение, где ключи уникальны. Set быстрее для операций проверки принадлежности и поиска. Dictionary удобен для поиска по ключу и хранения дополнительных данных для каждого ключа.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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
👍3
Можно создать структуру, которая будет использовать массивы пар ключ-значение, хэш-функции или реализовать собственную логику поиска, вставки и удаления. Это потребует понимания базовых алгоритмов хэширования.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2
Принцип OCP (Open-Closed Principle) гласит:
"Программные сущности должны быть открыты для расширения, но закрыты для модификации."
Это значит, что код должен позволять добавлять новый функционал без изменения существующего кода.
Меньше багов – изменения не ломают старый код.
Лучшая поддержка – новый функционал добавляется без переписывания старого.
Гибкость – можно расширять систему без изменения её базовой логики.
Допустим, у нас есть класс, который рисует фигуры:
class ShapeDrawer {
func draw(shape: String) {
if shape == "circle" {
print("Рисуем круг")
} else if shape == "square" {
print("Рисуем квадрат")
}
}
}Лучше использовать наследование или протоколы, чтобы расширять функциональность, не меняя существующий код:
protocol Drawable {
func draw()
}
class Circle: Drawable {
func draw() {
print("Рисуем круг")
}
}
class Square: Drawable {
func draw() {
print("Рисуем квадрат")
}
}
class ShapeDrawer {
func draw(shape: Drawable) {
shape.draw()
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Memory Graph в Xcode показывает живые объекты и их связи. Это полезно для поиска retain cycles, обнаружения неосвобождённых контроллеров и анализа структуры объектов. Доступен во время отладки через Debug Navigator.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift ключи в словаре (
Dictionary) должны быть уникальными и сравниваться между собой. Поэтому, если вы хотите использовать*свою структуру в качестве ключа, она должна соответствовать протоколу Hashable. Структура должна соответствовать
Hashable Должен быть реализован
hash(into:) или использовать Equatable + Hashable автоматически Свойства структуры должны быть
Hashable (если String, Int, Double – все ок) 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:):struct Person: Hashable {
let id: Int
let name: String
func hash(into hasher: inout Hasher) {
hasher.combine(id) // Используем только id для хеша
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
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