В основе Git Flow – несколько веток с разными ролями, чтобы команда могла параллельно разрабатывать новые фичи, исправлять баги и выпускать релизы.
-
main – содержит только стабильные версии. -
develop – основная ветка разработки, в неё вливаются все новые фичи. - Каждая новая фича создаётся в отдельной ветке
feature/*. - После завершения сливается в
develop. git checkout develop
git checkout -b feature/new-cool-feature
# Разработка...
git checkout develop
git merge feature/new-cool-feature
git branch -d feature/new-cool-feature
- Когда код стабилен, создаётся ветка
release/* от develop. - Здесь можно тестировать и исправлять баги.
- После финального теста сливается в
main и develop. git checkout develop
git checkout -b release/1.0
# Фиксим баги, тестируем...
git checkout main
git merge release/1.0
git tag -a v1.0 -m "Release 1.0"
git checkout develop
git merge release/1.0
git branch -d release/1.0
- Если критический баг в
main, создаём hotfix/*. - После исправления вливаем в
main и в develop. git checkout main
git checkout -b hotfix/urgent-bugfix
# Фиксим баг...
git checkout main
git merge hotfix/urgent-bugfix
git checkout develop
git merge hotfix/urgent-bugfix
git branch -d hotfix/urgent-bugfix
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
NSOperation — это объектно-ориентированный способ организации задач в iOS/macOS. Он позволяет управлять очередями задач с возможностью их приостановки, отмены, приоритезации и установления зависимостей между операциями. Работает в связке с NSOperationQueue. В отличие от GCD, даёт больше контроля и читаемости, особенно при работе со сложными асинхронными цепочками.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS и macOS приложениях, разработанных с использованием Swift или Objective-C,
UIView и CALayer играют ключевые роли в управлении и отображении пользовательского интерфейса. Несмотря на то, что они тесно связаны, между ними есть важные различия. Давайте рассмотрим их подробнее.UIView — это базовый класс для всех элементов пользовательского интерфейса в iOS. Он представляет собой прямоугольную область на экране, которая может отображать контент и реагировать на события пользователя, такие как нажатия, жесты и касания.UIView предоставляет множество свойств и методов для управления внешним видом, положением и поведением представления. Примеры включают frame, bounds, center, backgroundColor, alpha, isHidden, и subviews. UIView также поддерживает анимации, автолэйаут и работу с событийной системой.UIView обрабатывает пользовательские события, такие как касания и жесты. Он предоставляет методы, такие как touchesBegan, touchesMoved, и touchesEnded, для обработки этих событий.let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myView.backgroundColor = .blue
view.addSubview(myView)
CALayer — это базовый класс для всех графических слоев, используемых в Core Animation. Он обеспечивает низкоуровневую поддержку для рендеринга, анимации и композиции графики.CALayer предоставляет свойства для управления внешним видом, такими как backgroundColor, borderWidth, cornerRadius, shadowOpacity, contents (для отображения изображений), и transform. CALayer также поддерживает анимации, используя ключевые кадры и основные анимации. CALayer не обрабатывает пользовательские события напрямую. Эти задачи оставлены на UIView, который может содержать один или несколько слоев.let myLayer = CALayer()
myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myLayer.backgroundColor = UIColor.blue.cgColor
view.layer.addSublayer(myLayer)
UIView — это более высокий уровень абстракции, предназначенный для работы с пользовательским интерфейсом и обработкой событий. CALayer — более низкоуровневый элемент, который фокусируется на рендеринге и анимации графики.UIView обрабатывает события пользовательского интерфейса. CALayer не обрабатывает события, но предоставляет возможности для рендеринга и анимации.UIView может содержать другие представления (subviews) и управлять их иерархией. CALayer может содержать другие слои (sublayers) и управлять их иерархией.UIView использует UIView.animate для создания анимаций, которые высокоуровневые и просты в использовании. CALayer использует CAAnimation и его подклассы для создания анимаций, которые более гибкие и мощные, но требуют большего количества кода.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
- var — переменная, её значение можно изменить.
- let — константа, значение нельзя переопределить после инициализации.
Это помогает контролировать изменяемость данных в коде.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔2
В iOS существует несколько способов вёрстки пользовательского интерфейса. Каждый из них имеет свои плюсы и минусы в зависимости от проекта.
Используется: визуальный редактор в Xcode.
Storyboard
- Позволяет создавать весь UI в одном файле
.storyboard.- Поддерживает Auto Layout и Size Classes для адаптивного дизайна.
- Можно настраивать Segue (переходы между экранами).
Используется: Полностью программная вёрстка без использования Interface Builder.
let button = UIButton()
button.setTitle("Нажми", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
Используется: Современный способ верстки с декларативным синтаксисом.
struct ContentView: View {
var body: some View {
VStack {
Text("Привет, SwiftUI!")
.font(.largeTitle)
Button("Нажми меня") {
print("Кнопка нажата")
}
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
2. Высокий приоритет указывает, что элемент предпочитает оставаться минимального размера, основываясь на содержимом.
3. Используется для разрешения конфликтов автолейаута, чтобы определять, какой элемент должен изменяться.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
enum (перечисления) относится к типам значений (value types). Это означает, что при передаче перечисления функции или при его присвоении переменной создается новая копия этого перечисления. Это работает аналогично другим типам значений, таким как
struct и базовые типы данных (Int, String, Double и т.д.).Когда переменной перечисления присваивается значение другой переменной перечисления, создается независимая копия этого значения.
enum поддерживает безопасность типов, что позволяет создавать код, легкий для понимания и поддержки.enum может хранить связанные значения различных типов.enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
enum может иметь методы, которые предоставляют функциональность, связанную с перечислением.enum Planet {
case earth, mars, venus
func isHabitable() -> Bool {
switch self {
case .earth:
return true
default:
return false
}
}
}
Пример
enum TrafficLight {
case red, yellow, green
}
var light = TrafficLight.red
var lightCopy = light
lightCopy = .green
print(light) // Выводит "red"
print(lightCopy) // Выводит "green"Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊7🤔2
- Вью не участвует в hit-тестировании.
- Касания игнорируются, и управление не передаётся даже в её subviews.
- Это может использоваться для пропуска вью при касаниях, например для декоративных вьюшек или контейнеров.
Ситуации:
- Кнопка, которая кажется активной, но isUserInteractionEnabled = false — не реагирует.
- Обёртка вокруг интерактивной вью с отключенным взаимодействием — вложенные вью тоже не реагируют.
Чтобы вложенные вью реагировали, при этом контейнер не мешал, можно либо оставить userInteractionEnabled = true, либо использовать прозрачный hitTest.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Память устройства можно представить в виде нескольких уровней, каждый из которых имеет свою скорость доступа, размер и назначение:
Это самая быстрая память, непосредственно встроенная в процессор. Регистры хранят те данные, с которыми процессор работает в данный момент времени.
Она находится непосредственно на процессоре или рядом с ним. Кэш-память используется для временного хранения копий часто используемых данных из основной памяти для ускорения доступа к ним. Кэш-память делится на несколько уровней (L1, L2, и иногда L3), где L1 — самый быстрый и обычно самый маленький.
Здесь хранятся данные и программы, с которыми компьютер работает в данный момент. Доступ к ОЗУ быстрый, но оно является временным хранилищем: при выключении устройства данные в ОЗУ теряются.
Это память для долговременного хранения данных. Она сохраняет информацию даже при выключении питания. HDD (жесткие диски) использовались ранее и работают на принципе магнитного записывания данных, в то время как SSD (твердотельные накопители) работают на основе флеш-памяти и обеспечивают более быстрый доступ к данным.
Это техника, которая позволяет операционной системе использовать часть жесткого диска (или SSD) как дополнительную оперативную память. Когда ОЗУ заполнено, операционная система может перемещать редко используемые данные из ОЗУ на диск в специальный файл подкачки (swap file), освобождая ОЗУ для других задач.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Да, существуют два основных типа dispatch-очередей:
- Serial queue — задачи выполняются строго по одной, по порядку.
- Concurrent queue — задачи могут выполняться одновременно, в зависимости от доступных ресурсов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В Swift существует несколько видов диспетчеризации, которые определяют, как и когда вызываются методы или функции. Основные виды диспетчеризации включают статическую диспетчеризацию (static dispatch), диспетчеризацию по таблице виртуальных функций (vtable dispatch), диспетчеризацию по свидетелю (witness table dispatch) и динамическую диспетчеризацию (dynamic dispatch). Рассмотрим их подробнее:
Вызов функции или метода определяется на этапе компиляции. Используется для функций и методов, которые не переопределяются в подклассах или не являются динамическими. Для структур, перечислений и final классов.
struct MyStruct {
func printMessage() {
print("Hello from MyStruct")
}
}
let instance = MyStruct()
instance.printMessage() // Вызов определяется на этапе компиляции
Используется для вызова методов класса, которые могут быть переопределены в подклассах. Виртуальная таблица (vtable) используется для определения, какой метод вызывать. Для классов и их подклассов.
class BaseClass {
func printMessage() {
print("Hello from BaseClass")
}
}
class SubClass: BaseClass {
override func printMessage() {
print("Hello from SubClass")
}
}
let instance: BaseClass = SubClass()
instance.printMessage() // Вызов определяется в runtime с использованием vtable
Используется для вызова методов протоколов, реализованных типами. Таблица свидетелей (witness table) используется для определения, какой метод вызывать. Для типов, соответствующих протоколам.
protocol MyProtocol {
func printMessage()
}
struct MyStruct: MyProtocol {
func printMessage() {
print("Hello from MyStruct")
}
}
let instance: MyProtocol = MyStruct()
instance.printMessage() // Вызов определяется в runtime с использованием witness table
Используется для вызова методов, отмеченных как
dynamic или методов Objective-C. Метод определяется в runtime с использованием Objective-C runtime. Для методов, которые должны быть динамически разрешены в runtime, обычно для взаимодействия с Objective-C. import Foundation
class MyClass: NSObject {
@objc dynamic func printMessage() {
print("Hello from MyClass")
}
}
let instance = MyClass()
instance.printMessage() // Вызов определяется в runtime с использованием Objective-C runtime
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Замыкание — это референсный тип. Оно является объектом и передаётся по ссылке. При захвате переменных — сохраняет их в памяти до завершения использования.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
В контексте Swift термин Satisfiable (удовлетворяемый) относится к тому, может ли конкретный тип соответствовать (удовлетворять) требованиям протокола.
Протокол считается satisfiable, если его можно реализовать без противоречий. Например, если в протоколе указаны требования, которые могут быть выполнены в классе или структуре.
protocol Animal {
var name: String { get }
func speak()
}
struct Dog: Animal {
var name = "Барсик"
func speak() {
print("Гав-гав")
}
}
let dog = Dog()
dog.speak() // "Гав-гав"Протокол не может быть удовлетворён (то есть, не satisfiable), если он содержит требования, которые невозможно реализовать в конкретном типе.
protocol Impossible {
var value: Self { get } // Self требует, чтобы свойство содержало сам тип
}
struct Example: Impossible {
var value: Example // ОШИБКА: бесконечная рекурсия!
}Если вы видите ошибку Protocol 'X' cannot be satisfied, значит, Swift не может найти способ правильно реализовать все его требования.
Проверьте ассоциированные типы и
Self – они должны корректно ссылаться на реализуемый тип.Проверьте требования протокола – убедитесь, что все свойства и методы могут быть реализованы в классе/структуре.
Попробуйте использовать
any Protocol – если Self создаёт проблемы, возможно, нужно использовать any: func test(value: any Impossible) { } // Позволяет работать с протоколом без строгого SelfСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Зависит от языка:
- В Python или Swift, копирование изменяемого массива создаёт новый массив, но если элементы — ссылки на объекты, то копируются ссылки, а не сами объекты (поверхностная копия).
- В других языках может быть как поверхностная, так и глубокая копия, в зависимости от реализации. Копия — это независимая структура, но её элементы могут по-прежнему ссылаться на одни и те же объекты.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2
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
Это механизм анимации в SwiftUI, позволяющий плавно анимировать переходы между представлениями, сохраняя визуальную взаимосвязь между элементами, которые логически одинаковые, но физически находятся в разных частях UI.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Обеспечение безопасности работы с историей изображений в iOS-приложениях может включать несколько уровней защиты:
- Используйте Privacy Settings (
NSPhotoLibraryUsageDescription, NSCameraUsageDescription) для контроля доступа к фотоальбому. - Для ограниченного доступа в iOS 14+ используйте
PHPickerViewController. let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
if status == .authorized {
// Доступ есть
} else {
// Запросить разрешение
PHPhotoLibrary.requestAuthorization { newStatus in
if newStatus == .authorized {
print("Доступ получен")
}
}
}
- Если изображения сохраняются локально, используйте AES-шифрование.
- Можно хранить ключ в Keychain или использовать Secure Enclave.
import CommonCrypto
func encryptImage(data: Data, key: Data) -> Data? {
var buffer = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0
let status = CCCrypt(
CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding), key.bytes, key.count,
nil, data.bytes, data.count, &buffer, buffer.count, &numBytesEncrypted
)
return status == kCCSuccess ? buffer.prefix(numBytesEncrypted) : nil
}
Core Data с Encrypted Store – можно использовать зашифрованные базы данных, такие как
SQLCipher. FileManager + Data Protection – файлы можно хранить в
Application Support с флагом .completeFileProtection. Keychain – если нужно хранить ссылки на изображения или ключи.
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("secure_image.jpg")
try? imageData.write(to: fileURL, options: .completeFileProtection)- Если изображение чувствительное, отключите кеширование в
URLSession: let config = URLSessionConfiguration.default
config.urlCache = nil // Отключаем кеш
let session = URLSession(configuration: config)
- Убедитесь, что ссылки на изображения не создают retain cycle.
- Используйте weak ссылки в кэше изображений.
class ImageCache {
private let cache = NSCache<NSString, UIImage>()
func store(image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}
func retrieve(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
}- Используйте HTTPS вместо HTTP.
- Включите App Transport Security (ATS) в
Info.plist. - Верифицируйте SSL-сертификаты при загрузке.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if let serverTrust = challenge.protectionSpace.serverTrust {
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
static используется для определения методов и свойств, которые принадлежат типу, а не экземпляру. Внутри классов static по сути означает final, так как такие методы нельзя переопределить в подклассах.
final, в свою очередь, может применяться к классам, методам и свойствам, чтобы запретить наследование или переопределение, но не обязательно делает метод или свойство статическим.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Это классификация различных видов данных, которые могут быть использованы и манипулированы в программе. Они определяют, какие операции можно выполнять с данными и как они хранятся в памяти.
Представляют целые числа.
Int, UInlet age: Int = 25
Представляют дробные числа.
Float, Doublelet pi: Double = 3.14159
Представляют логические значения
true или false. Boollet isActive: Bool = true
Представляют отдельные символы.
Characterlet letter: Character = "A"
Представляют последовательности символов.
Stringlet greeting: String = "Hello, World!"
Представляют упорядоченные коллекции элементов одного типа.
Array<T>let numbers: [Int] = [1, 2, 3, 4, 5]
Представляют коллекции пар ключ-значение.
Dictionary<Key, Value>let user: [String: String] = ["name": "Alice", "age": "30"]
Представляют коллекции уникальных элементов.
Set<T>let uniqueNumbers: Set<Int> = [1, 2, 3, 4, 5]
Представляют тип данных с набором связанных значений.
enum enum CompassPoint {
case north
case south
case east
case west
}
Представляют группы связанных значений.
struct struct Person {
var name: String
var age: Int
}
let person = Person(name: "Alice", age: 30)
Представляют объекты с состоянием и поведением.
class class Car {
var model: String
var year: Int
init(model: String, year: Int) {
self.model = model
self.year = year
}
}
let car = Car(model: "Tesla", year: 2021)
Представляют группы нескольких значений различных типов.
(Type1, Type2, ...)let coordinates: (Int, Int) = (10, 20)
Представляют значение, которое может быть либо некоторым значением, либо nil.
Optional<T>var optionalName: String? = "Alice"
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
- Эти вьюшки не двигаются физически — они находятся в contentView, которая движется вместе с contentOffset.
- Относительно ScrollView они могут визуально выходить за пределы видимости, но физически остаются на месте внутри большого contentSize.
Если вью ушла за пределы видимой области, она не рендерится до тех пор, пока не попадёт в видимую область (оптимизация).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2