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
Синхронные и асинхронные соединения имеют свои уникальные преимущества и недостатки. Понимание этих различий важно для правильного выбора подхода в зависимости от контекста и требований приложения.
Плюсы
Синхронные операции проще понимать и реализовывать, так как они выполняются последовательно.
Отладка синхронного кода проще, так как последовательность выполнения предсказуема.
Синхронный код выполняется по порядку, что делает логику более прозрачной.
Минусы
Синхронные операции могут блокировать основной поток выполнения, что приводит к замедлению работы интерфейса или приложения в целом.
Приложения с синхронными операциями могут становиться менее отзывчивыми, так как долгие операции могут замораживать пользовательский интерфейс.
Синхронный подход может ограничивать возможности масштабирования, так как каждая операция ожидает завершения предыдущей.
Плюсы
Асинхронные операции позволяют выполнять другие задачи, не дожидаясь завершения долгих операций, что увеличивает общую производительность приложения.
Асинхронный подход позволяет поддерживать отзывчивость пользовательского интерфейса, так как долгие операции выполняются в фоновом режиме.
Асинхронный код лучше масштабируется, так как позволяет обрабатывать множество запросов одновременно.
Минусы
Асинхронные операции требуют более сложной реализации и понимания концепций, таких как колбэки, промисы или async/await.
Отладка асинхронного кода может быть сложнее из-за непредсказуемой последовательности выполнения.
Асинхронные операции могут приводить к неопределенным состояниям, если не обрабатывать их правильно, что может привести к трудноуловимым ошибкам.
Синхронный пример
func fetchDataSynchronously() {
let url = URL(string: "https://api.example.com/data")!
let data = try? Data(contentsOf: url)
if let data = data {
print("Данные загружены: \(data)")
} else {
print("Ошибка загрузки данных")
}
}Асинхронный пример
func fetchDataAsynchronously() {
let url = URL(string: "https://api.example.com/data")!
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
print("Данные загружены: \(data)")
} else if let error = error {
print("Ошибка загрузки данных: \(error)")
}
}.resume()
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это модификатор, который предотвращает изменения:
- Класс: нельзя наследовать.
- Метод: нельзя переопределять.
- Переменная: значение нельзя изменить после инициализации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Не поддерживает множественное наследование для классов, что является общим выбором в современных объектно-ориентированных языках программирования из-за сложностей и проблем, которые множественное наследование может создать (например, проблема алмаза смерти). Однако предлагаются альтернативные механизмы, позволяющие имитировать некоторые аспекты множественного наследования.
Похожи на интерфейсы в других языках. Они позволяют классам, структурам и перечислениям принимать "контракты", которые определяют методы и свойства, которые должны быть реализованы. Протоколы могут наследоваться и расширяться, предоставляя гибкий способ добавления функциональности к типам.
protocol Movable {
func move()
}
protocol Drawable {
func draw()
}
class Character: Movable, Drawable {
func move() {
print("Персонаж двигается")
}
func draw() {
print("Персонаж рисуется")
}
}
Позволяют добавлять новую функциональность к существующим типам, включая те, которые определены в стандартной библиотеке или внешних библиотеках. Хотя расширения не могут добавлять хранимые свойства, они могут добавлять новые вычисляемые свойства, методы и протоколы.
extension Character: Drawable {
func draw() {
print("Персонаж рисуется через расширение")
}
}Это альтернативный подход к наследованию, при котором один тип включает другой как часть своей реализации, вместо того чтобы наследовать от него. Это предпочтительный метод для достижения повторного использования кода, позволяющий избежать ограничений и сложностей наследования.
class Engine {
func start() {
print("Двигатель запущен")
}
}
class Car {
let engine = Engine()
func startEngine() {
engine.start()
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
- Layer: низкоуровневый компонент (из Core Animation), который отвечает за рендеринг содержимого и может использоваться для сложных анимаций или оптимизаций.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1