Это сообщения, которые отправляются приложением пользователю даже тогда, когда само приложение не активно. Это эффективный способ удержания пользователей и предоставления им важной информации.
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения 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
👍3
1. Основа — выявление узких мест с помощью профайлеров.
2. Важно оптимизировать только критические участки, чтобы не усложнять код.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это функции, которые вы можете применять к вьюшкам (представлениям), чтобы изменить их внешний вид или поведение. Они возвращают новое представление с измененными свойствами, позволяя вам легко настраивать элементы интерфейса. Модификаторы являются неотъемлемой частью декларативного подхода SwiftUI, где вы описываете, что должно быть сделано, а не как.
Изменяет фон представления.
Text("Привет, мир!")
.background(Color.yellow) Добавляет границу вокруг представления.
Text("Привет, мир!")
.border(Color.red, width: 2) Добавляет отступы вокруг содержимого представления.
Text("Привет, мир!")
.padding()
Добавляет тень к представлению.
Text("Привет, мир!")
.shadow(color: .black, radius: 2, x: 0, y: 2) Закругляет углы представления.
Text("Привет, мир!")
.background(Color.blue)
.cornerRadius(10) Устанавливает размеры представления.
Text("Привет, мир!")
.frame(width: 200, height: 50)
Пример использования нескольких модификаторов
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.padding() // Добавляем отступы
.background(Color.yellow) // Фон желтого цвета
.cornerRadius(10) // Закругляем углы
.shadow(color: .gray, radius: 5, x: 0, y: 5) // Добавляем тень
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Загружать изображения асинхронно, избегая блокировки основного потока.
3. Применять сжатие или адаптивные форматы изображений.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Применение модификатора к вью в SwiftUI изменяет его внешний вид или поведение. Каждый модификатор возвращает новое представление с измененными свойствами, не изменяя исходное представление. Это позволяет создавать сложные пользовательские интерфейсы, применяя цепочки модификаторов.
Модификаторы могут изменять визуальные характеристики вью, такие как цвет, шрифт, отступы и границы.
Text("Привет, мир!")
.padding() // Добавляет отступы вокруг текста
.background(Color.yellow) // Устанавливает желтый фон
.cornerRadius(10) // Закругляет углы текстаМодификаторы могут изменять поведение вью, такие как обработка событий и взаимодействие.
Button(action: {
print("Кнопка нажата")
}) {
Text("Нажми меня")
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10) Модификаторы могут изменять размеры и позиционирование вью.
Text("Привет, мир!")
.frame(width: 200, height: 50) // Устанавливает размеры вью
.padding()
.background(Color.green) Пример с пояснением
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.padding() // Добавляет отступы вокруг текста
.background(Color.yellow) // Устанавливает желтый фон
.cornerRadius(10) // Закругляет углы текста
.shadow(color: .gray, radius: 5, x: 0, y: 5) // Добавляет тень
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
2. Mutex: обеспечивает эксклюзивный доступ к ресурсу для одного потока.
3. Основное отличие в уровне параллелизма: mutex работает с одним потоком, а semaphore с несколькими.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Это протокол, который позволяет создавать собственные модификаторы для вьюшек. Он позволяет инкапсулировать повторяющиеся изменения внешнего вида и поведения вью в отдельные, легко переиспользуемые компоненты. Это помогает сократить дублирование кода и улучшает читаемость и поддерживаемость приложения.
Чтобы создать собственный модификатор, нужно реализовать протокол
ViewModifier, который требует определения метода body(content:), возвращающего измененное представление.Допустим, мы хотим создать модификатор, который добавляет отступы, фон, закругленные углы и тень к вью.
import SwiftUI
// Создаем кастомный модификатор
struct CustomModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding() // Добавляем отступы
.background(Color.yellow) // Устанавливаем фон
.cornerRadius(10) // Закругляем углы
.shadow(color: .gray, radius: 5, x: 0, y: 5) // Добавляем тень
}
}
extension View {
func customStyle() -> some View {
self.modifier(CustomModifier())
}
}
struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.customStyle() // Применяем наш кастомный модификатор
}
}
struct CustomModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color.yellow)
.cornerRadius(10)
.shadow(color: .gray, radius: 5, x: 0, y: 5)
}
}
extension View {
func customStyle() -> some View {
self.modifier(CustomModifier())
}
}
struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.customStyle()
}
}
Модификаторы позволяют инкапсулировать часто используемые изменения и применять их в разных частях приложения.
Применение модификаторов упрощает и сокращает код, делая его более читаемым.
Выделение стилей и поведения в отдельные модификаторы улучшает структуру кода и упрощает его поддержку.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Улучшенная тестируемость: каждый модуль легко тестируется независимо.
3. Масштабируемость: упрощается добавление новых функций без влияния на существующий код.
4. Поддерживаемость: из-за чёткого разграничения слоёв снижается сложность сопровождения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Это способ добавить дополнительное поведение к свойствам без дублирования кода. Они позволяют инкапсулировать логику и применять её к различным свойствам, упрощая управление состоянием и поведением.
@propertyWrapper
struct Logging<Value> {
private var value: Value
var wrappedValue: Value {
get { value }
set {
print("Значение изменилось с \(value) на \(newValue)")
value = newValue
}
}
init(wrappedValue: Value) {
self.value = wrappedValue
}
}
struct User {
@Logging var name: String
@Logging var age: Int
}
var user = User(name: "Алексей", age: 25)
user.name = "Иван" // Консоль: Значение изменилось с Алексей на Иван
user.age = 26 // Консоль: Значение изменилось с 25 на 26Основное свойство, которое обёртка обрабатывает. При чтении и записи этого свойства выполняется дополнительная логика, определённая в обёртке.
Инициализатор для установки начального значения свойства. Этот инициализатор делает возможным использование обёртки при объявлении свойств.
Swift предоставляет несколько встроенных обёрток свойств, которые широко используются в SwiftUI и Combine.
Управляет состоянием внутри вью.
struct ContentView: View {
@State private var counter = 0
var body: some View {
VStack {
Text("Счётчик: \(counter)")
Button("Увеличить счётчик") {
counter += 1
}
}
}
}
Объявляет свойство, которое оповещает подписчиков о своих изменениях.
class ViewModel: ObservableObject {
@Published var message: String = "Привет"
}
Используется для наблюдения за объектом, который реализует протокол
ObservableObject. struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.message)
}
}
Обёртки позволяют инкапсулировать повторяющуюся логику и применять её к различным свойствам.
Использование обёрток делает код более чистым и удобным для чтения.
Логика управления состоянием и поведением свойств инкапсулируется внутри обёртки, что делает её независимой и легко тестируемой.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Применять мьютексы или семафоры для управления доступом к ресурсам.
3. Использовать NSLock или DispatchQueue.sync для работы с общими данными.
4. Применять атомарные операции (OSAtomic, DispatchSemaphore) для минимизации конфликтов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift property wrappers, которые объявляют reference семантику, позволяют объектам, обёрнутым этими обёртками, сохранять ссылочную семантику. Это значит, что при передаче таких объектов они будут передаваться по ссылке, а не по значению, как это обычно происходит со структурами.
Используется для отслеживания изменений в объекте, который реализует протокол
ObservableObject. Когда такие объекты изменяются, представления, которые наблюдают за ними, автоматически обновляются. import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var message: String = "Привет"
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.message)
}
}
Этот property wrapper используется для инициализации и хранения экземпляра объекта, который реализует
ObservableObject, обеспечивая правильное управление жизненным циклом объекта в пределах вью. Он гарантирует, что объект будет инициализирован один раз и не будет уничтожен при повторном рендеринге вью. import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var message: String = "Привет"
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.message)
}
}
Используется для передачи данных через иерархию представлений, чтобы любое представление в иерархии могло получить доступ к объекту. Этот объект должен быть доступен в окружающей среде представления.
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var message: String = "Привет"
}
struct ParentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ChildView()
.environmentObject(viewModel)
}
}
struct ChildView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
Text(viewModel.message)
}
}
Используется для наблюдения за объектом, который создаётся и управляется вне текущего представления.
Используется для создания и управления объектом в текущем представлении, обеспечивая правильное управление его жизненным циклом.
Используется для передачи объектов через несколько представлений, обеспечивая доступ к ним в любом представлении иерархии.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
2. Ключевые кадры: CAKeyframeAnimation для сложных траекторий.
3. Групповые анимации: CAAnimationGroup для одновременного выполнения нескольких анимаций.
4. UIView-анимации: простые и удобные для UI (например, UIView.animate).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Property wrappers с value семантикой в Swift работают с типами, которые копируются при присваивании. Это означает, что при передаче таких объектов создаются их копии, и изменения в одной копии не влияют на другие. В Swift такие property wrappers часто используются для управления состоянием и других аспектов данных, которые должны копироваться при изменении.
Используется для хранения состояния в пределах представления. Когда состояние изменяется, представление автоматически обновляется для отображения нового состояния.
import SwiftUI
struct ContentView: View {
@State private var counter = 0
var body: some View {
VStack {
Text("Счётчик: \(counter)")
Button("Увеличить счётчик") {
counter += 1
}
}
}
}
Используется для создания связи между источником данных и представлением, позволяя передавать состояние между представлениями.
@Binding позволяет двум представлениям разделять одно и то же состояние. import SwiftUI
struct ParentView: View {
@State private var counter = 0
var body: some View {
ChildView(counter: $counter)
}
}
struct ChildView: View {
@Binding var counter: Int
var body: some View {
Button("Увеличить счётчик") {
counter += 1
}
}
}
Используется для хранения значений в UserDefaults. Позволяет легко сохранять и извлекать данные из постоянного хранилища.
import SwiftUI
struct ContentView: View {
@AppStorage("username") private var username: String = "Гость"
var body: some View {
VStack {
Text("Имя пользователя: \(username)")
Button("Изменить имя") {
username = "Алексей"
}
}
}
}
Используется для хранения данных, специфичных для сцены, которые сохраняются и восстанавливаются при сворачивании и развертывании сцены.
import SwiftUI
struct ContentView: View {
@SceneStorage("note") private var note: String = ""
var body: some View {
TextField("Введите заметку", text: $note)
.padding()
}
}
Управляет состоянием в пределах одного представления.
Создаёт связь между состоянием в разных представлениях, позволяя одному представлению изменять состояние другого.
Хранит данные в UserDefaults, позволяя сохранять и восстанавливать их между сеансами приложения.
Хранит данные, специфичные для сцены, которые сохраняются при сворачивании и развертывании сцены.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
2. Параллельные (concurrent): задачи выполняются одновременно.
3. Главная очередь (main queue): предназначена для обновления UI.
4. Глобальные очереди (global queues): используются для фоновых задач.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Начиная с iOS 17, Apple представила новый способ сделать класс наблюдаемым с помощью атрибута
@Observable и свойства @Published. Этот подход упрощает создание наблюдаемых объектов и улучшает интеграцию с SwiftUI.import SwiftUI
@Observable
class ViewModel {
@Published var message: String = "Привет, мир!"
}
Теперь мы можем использовать наш наблюдаемый объект в SwiftUI, и представление будет автоматически обновляться при изменении свойств, помеченных как
@Published. struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
VStack {
Text(viewModel.message)
Button("Изменить сообщение") {
viewModel.message = "Привет, SwiftUI!"
}
}
}
}Полный пример использования наблюдаемого класса в SwiftUI
import SwiftUI
@Observable
class ViewModel {
@Published var message: String = "Привет, мир!"
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
VStack {
Text(viewModel.message)
Button("Изменить сообщение") {
viewModel.message = "Привет, SwiftUI!"
}
}
}
}
Пример использования @EnvironmentObject
import SwiftUI
@Observable
class ViewModel {
@Published var message: String = "Привет, мир!"
}
struct ParentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
ChildView()
.environmentObject(viewModel)
}
}
struct ChildView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
VStack {
Text(viewModel.message)
Button("Изменить сообщение") {
viewModel.message = "Привет, SwiftUI!"
}
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👾1
2. Делегаты: передача данных через протоколы.
3. Замыкания: использование callback-функций.
4. Уведомления: через NotificationCenter.
5. Кросс-контроллеры: с использованием segue или Dependency Injection.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Сцены и фазы переходов (Scene phases and transitions) — важные аспекты управления состоянием приложения в SwiftUI, особенно когда речь идет о многозадачности и жизненном цикле приложения. SwiftUI предоставляет механизмы для обработки этих состояний и переходов через специальные property wrappers и API.
Приложение активно и отображает контент на экране.
Приложение находится на переднем плане, но не взаимодействует с пользователем (например, при входящем вызове).
Приложение находится в фоне и не отображается на экране.
Пример использования @Environment(\.scenePhase)
import SwiftUI
struct ContentView: View {
@Environment(\.scenePhase) var scenePhase
var body: some View {
Text("Привет, мир!")
.onChange(of: scenePhase) { newPhase in
switch newPhase {
case .active:
print("Сцена активна")
case .inactive:
print("Сцена неактивна")
case .background:
print("Сцена в фоне")
@unknown default:
print("Неизвестное состояние сцены")
}
}
}
}
Переходы между фазами сцены происходят автоматически, когда пользователь взаимодействует с приложением или системой. Однако важно правильно обрабатывать эти переходы, чтобы обеспечить корректную работу приложения, например, сохранять данные при переходе в фоновый режим.
Для приложений, использующих
UIKit и SwiftUI вместе, обработка фаз сцены может выполняться в классе SceneDelegate. import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Сцена стала активной
print("Сцена активна")
}
func sceneWillResignActive(_ scene: UIScene) {
// Сцена станет неактивной
print("Сцена неактивна")
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Сцена перешла в фоновый режим
print("Сцена в фоне")
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Сцена перейдет в передний план
print("Сцена на переднем плане")
}
}
Позволяет сохранять важные данные, когда приложение переходит в фоновый режим, и восстанавливать их при возвращении.
Позволяет освобождать ресурсы, когда приложение не активно, и выделять их, когда оно становится активным.
Обеспечивает плавный и предсказуемый опыт для пользователя при смене состояний приложения.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Direct Dispatch: прямой вызов метода без участия vtable.
3. Protocol Witness Table (PWT): используется для вызовов методов, реализованных через протоколы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В SwiftUI существует несколько модификаторов, которые позволяют изменять и обрабатывать события жизненного цикла вью. Эти модификаторы помогают реагировать на различные состояния представления и управлять его поведением.
Выполняет действие, когда представление появляется на экране.
Выполняет действие, когда представление исчезает с экрана.
Выполняет асинхронное действие при появлении представления на экране.
Реагирует на изменения определенного состояния или значения.
Реагирует на обновления из
Publisher.onAppear выполняет действие, когда представление появляется на экране. struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.onAppear {
print("Представление появилось на экране")
}
}
}onDisappear выполняет действие, когда представление исчезает с экрана. struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.onDisappear {
print("Представление исчезло с экрана")
}
}
}task выполняет асинхронное действие при появлении представления на экране. Это полезно для загрузки данных или выполнения других асинхронных задач. struct ContentView: View {
var body: some View {
Text("Привет, мир!")
.task {
await loadData()
}
}
func loadData() async {
// Асинхронная загрузка данных
print("Данные загружаются")
}
}onChange реагирует на изменения определенного состояния или значения. struct ContentView: View {
@State private var counter = 0
var body: some View {
VStack {
Text("Счётчик: \(counter)")
Button("Увеличить счётчик") {
counter += 1
}
}
.onChange(of: counter) { newValue in
print("Счётчик изменился на \(newValue)")
}
}
}onReceive реагирует на обновления из Publisher. Это полезно для обработки данных из Combine. import Combine
struct ContentView: View {
@State private var data: String = "Загрузка..."
let publisher = PassthroughSubject<String, Never>()
var body: some View {
Text(data)
.onReceive(publisher) { value in
data = value
}
}
}
Легко управлять состоянием представлений в различные моменты их жизненного цикла.
Выполнение асинхронных задач, таких как загрузка данных, при появлении представлений на экране.
Реакция на изменения состояний и значений в представлении.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2