В старых версиях iOS (до iOS 6),
IBOutlet переменные обычно освобождались (релизились) в методе viewDidUnload, чтобы освободить память. Это было связано с управлением памятью и ресурсами на устройствах с ограниченными ресурсами. Устройства с ограниченными ресурсами могли столкнуться с нехваткой памяти. Освобождение ресурсов, связанных с представлениями, помогало улучшить производительность приложения и предотвращало его крах.
viewDidUnload вызывался, когда система освобождала память, удаляя невидимые представления. В этом методе освобождались ресурсы, которые можно было легко пересоздать при следующем отображении представления.До iOS 6, код мог выглядеть так
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel?
override func viewDidUnload() {
super.viewDidUnload()
// Освобождение IBOutlet
myLabel = nil
}
}С введением автоматического управления памятью (ARC) и изменений в iOS 6, метод
viewDidUnload был устаревшим и удалённым. Теперь система управления памятью в iOS гораздо эффективнее, и необходимость вручную освобождать IBOutlet-ы больше не актуальна. Вместо этого представления и связанные с ними ресурсы освобождаются автоматически, когда они больше не нужны.Сейчас мы просто используем ARC и не беспокоимся об освобождении IBOutlet-ов
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Настройка myLabel
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
1. Более высокий приоритет заставляет элемент занимать минимальное пространство.
2. Это полезно при настройке адаптивных интерфейсов и разрешении конфликтов автолейаута.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Это метод, который вызывается после того, как объект был загружен из файла XIB или NIB. Этот метод используется для выполнения дополнительной настройки после загрузки объекта.
Этот метод вызывается, когда объект создается из XIB или NIB файла. Это место для выполнения дополнительных операций по настройке, которые не могут быть выполнены в Interface Builder.
class CustomView: UIView {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Дополнительная настройка
label.text = "Hello, World!"
}
}XIB файлы — это XML файлы, которые содержат описание интерфейса. XIB файлы редактируются в Interface Builder, который предоставляет визуальный способ создания и настройки интерфейсов. XIB файлы компилируются в NIB файлы во время сборки приложения.
NIB файлы — это двоичные файлы, которые содержат скомпилированное описание интерфейса. NIB файлы были использованы в ранних версиях macOS и iOS, а также в NeXTSTEP, на основе которого была построена macOS. Приложение загружает NIB файлы в память во время выполнения для создания и настройки интерфейсов.
XIB: XML-файл, который читается и редактируется в текстовом формате. NIB: Скомпилированный двоичный файл, который загружается в память во время выполнения.
XIB: Редактируется в Interface Builder. NIB: Содержит скомпилированные данные и не редактируется напрямую.
XIB: Используется для разработки и редактирования интерфейсов. NIB: Загружается и используется приложением во время выполнения.
class CustomView: UIView {
@IBOutlet weak var label: UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)
addSubview(label)
label.frame = self.bounds
}
override func awakeFromNib() {
super.awakeFromNib()
// Дополнительная настройка
label.text = "Hello, World!"
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
2. viewWillAppear: вызывается перед отображением на экране.
3. viewDidAppear: вызывается сразу после отображения.
4. viewWillDisappear и viewDidDisappear: перед и после удаления представления с экрана.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👾1
Это корневой класс для большинства классов в iOS. Он предоставляет базовую функциональность, такую как управление памятью (retain, release), метод доступа к информации о классе (class), и многое другое.
Этот класс отвечает за обработку событий, таких как касания экрана.
UIResponder является базовым классом для всех объектов, которые могут реагировать на события.UIView является базовым классом для всех визуальных элементов интерфейса. Он предоставляет функциональность для управления рамками, трансформациями, слоями (CALayer), анимациями и жестами.UIControl наследуется от UIView и добавляет поддержку механизма целевых действий (target-action) и управление состояниями (например, включено/выключено). Он является базовым классом для всех элементов управления, таких как кнопки, переключатели и слайдеры.Наконец,
UIButton наследуется от UIControl и представляет собой конкретную реализацию элемента управления, который реагирует на касания и может выполнять действия при нажатии. Он предоставляет дополнительные свойства и методы для настройки заголовка, изображения и фона кнопки.import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Создаем кнопку
let button = UIButton(type: .system)
button.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
button.setTitle("Нажми меня", for: .normal)
// Добавляем целевое действие для кнопки
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
// Добавляем кнопку на экран
self.view.addSubview(button)
}
@objc func buttonTapped() {
print("Кнопка была нажата!")
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
1. Set быстрее для поиска и вставки, но порядок элементов не сохраняется.
2. Для упорядоченных данных предпочтителен Array.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Это сообщения, которые отправляются приложением пользователю даже тогда, когда само приложение не активно. Это эффективный способ удержания пользователей и предоставления им важной информации.
Когда приложение устанавливается и запускается на устройстве, оно регистрируется для получения 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