Каждый способ создания макетов (layout'а) в iOS-разработке имеет свои преимущества и недостатки.
Удобный графический интерфейс для быстрой настройки и визуального просмотра изменений.
Простая настройка ограничений (constraints) для адаптивного интерфейса.
Возможность быстрого создания и изменения макетов без написания кода.
Ограниченные возможности для создания сложных и динамических макетов.
Трудности при слиянии изменений в storyboard или xib файлах в больших командах.
Более медленное время загрузки по сравнению с программными подходами.
Поддержка различных устройств и ориентаций экрана.
Возможность создания сложных и адаптивных макетов с помощью ограничений.
Упрощенная настройка ограничений через визуальный интерфейс.
Может быть сложно освоить, особенно для новичков.
Требует тщательного планирования и может стать сложным при работе с большим количеством ограничений.
Возможность точной настройки макета с помощью кода.
Легкость создания динамических и условных макетов.
Легче управлять изменениями в коде по сравнению с визуальными файлами.
Требует больше времени и усилий для настройки, особенно для сложных макетов.
Отсутствие визуального редактора может затруднить представление конечного результата.
Легкость создания и управления сложными макетами с минимальными усилиями.
Автоматическое управление ограничениями для вложенных элементов.
Поддержка различных ориентаций и размеров экранов.
Менее гибкие по сравнению с чистым Auto Layout или программными подходами.
Не всегда подходят для всех типов макетов, особенно для более сложных компоновок.
Простота и понятность кода благодаря декларативному подходу.
Мгновенное обновление интерфейса при изменении кода.
Современные возможности языка и тесная интеграция с экосистемой Apple.
Поддержка различных платформ (iOS, macOS, watchOS, tvOS).
Поддержка только iOS 13 и выше, что может ограничить использование на старых устройствах.
Некоторые функции еще находятся в стадии разработки, и могут быть ограничены возможности по сравнению с UIKit.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
RunLoop работает только на потоках, где он был явно создан. У каждой main queue и кастомного потока может быть свой RunLoop. Фоновым очередям в GCD RunLoop не нужен по умолчанию, пока не используется таймер или input source.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift нет множественного наследования классов, но можно использовать множественное наследование через протоколы.
Swift запрещает множественное наследование классов, потому что оно может привести к конфликтам и алмазной проблеме (diamond problem).
Допустим, в языке с поддержкой множественного наследования у нас есть два родительских класса с одинаковым методом:
class A {
public:
void greet() { cout << "Hello from A"; }
};
class B {
public:
void greet() { cout << "Hello from B"; }
};
// C наследуется от A и B
class C : public A, public B {};
C obj;
obj.greet(); // Какой метод вызвать? A или B?В Swift можно реализовать множественное наследование через протоколы, поскольку класс может соответствовать нескольким протоколам одновременно.
protocol Flyable {
func fly()
}
protocol Swimmable {
func swim()
}
class Animal {}
class Duck: Animal, Flyable, Swimmable {
func fly() {
print("Утка летит")
}
func swim() {
print("Утка плывёт")
}
}
let duck = Duck()
duck.fly() // Утка летит
duck.swim() // Утка плывётЕсли хочется, чтобы протокол предоставлял реализацию по умолчанию (почти как родительский класс), можно использовать
extension:protocol Walker {
func walk()
}
extension Walker {
func walk() {
print("Иду вперёд")
}
}
class Person: Walker {}
let human = Person()
human.walk() // "Иду вперёд" (метод взят из extension)Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- ARC работает сразу, как только счётчик = 0 (детерминированное управление);
- GC (в Java, Python) работает фоново, периодически сканируя объекты. Он может задерживать удаление, но справляется с циклами ссылок. ARC не умеет разрывать retain cycle — нужно вручную применять weak.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Swift (и во многих других языках программирования) по умолчанию числовой литерал с плавающей запятой интерпретируется как `Double`, а не
Float. Double имеет 64 бита, а Float – 32 бита. Это значит, что Double может хранить более точные значения, что особенно важно при математических вычислениях.Большинство API и стандартных библиотек Swift (например,
sin(), cos(), pow()) работают именно с Double. Например:
let x = 3.14 // По умолчанию это Double
let y = sin(x) // sin() принимает Double
На современных 64-битных процессорах операции с
Double выполняются так же быстро или даже быстрее, чем с Float, из-за оптимизаций в аппаратном обеспечении.Float может округлять числа с потерей точности, что может привести к неожиданным результатам. Пример ошибки округления в
Float:let a: Float = 0.1 + 0.2
print(a == 0.3) // false 😱
Если всё же нужен
Float, надо указать это явно:let number: Float = 3.14
или
let number = 3.14 as Float
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Принцип абстракции и обобщения. Дженерики позволяют создавать универсальные и типобезопасные компоненты, не дублируя код для каждого типа.
Также они поддерживают принцип повторного использования и инкапсуляцию логики.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В 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
Witness table — механизм Swift для протоколов, в ней хранится соответствие реализаций протокольным методам.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это абстрактная структура данных, работающая по принципу LIFO (Last In, First Out), что означает "последний пришёл — первый вышел". Это значит, что последний добавленный элемент будет первым при извлечении из стека. Под капотом реализации стека могут быть разные, и они зависят от конкретного языка программирования и задач, которые необходимо решить.
Один из самых распространённых способов реализации стека — это использование массива. В такой реализации элементы стека хранятся в массиве, и индекс последнего элемента (вершина стека) отслеживается отдельной переменной.
struct Stack<Element> {
private var storage: [Element] = []
mutating func push(_ element: Element) {
storage.append(element)
}
mutating func pop() -> Element? {
return storage.popLast()
}
func peek() -> Element? {
return storage.last
}
var isEmpty: Bool {
return storage.isEmpty
}
}Стек можно реализовать с использованием связных списков, где каждый элемент списка содержит данные и ссылку на следующий элемент в стеке. Вершина стека в такой реализации — это начало связного списка.
class Node<Element> {
var value: Element
var next: Node?
init(value: Element) {
self.value = value
}
}
struct Stack<Element> {
private var head: Node<Element>?
mutating func push(_ element: Element) {
let node = Node(value: element)
node.next = head
head = node
}
mutating func pop() -> Element? {
let node = head
head = head?.next
return node?.value
}
func peek() -> Element? {
return head?.value
}
var isEmpty: Bool {
return head == nil
}
}Это системный стек, который используется во время выполнения программы для хранения информации о вызовах функций/методов. Он хранит адреса возврата, параметры функций, локальные переменные и другие данные, необходимые для управления вызовами функций и их возврата.
Обратную польскую нотацию для вычисления арифметических выражений. Управление вызовами функций в программном стеке. Поддержка операций undo в приложениях.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Pod — это библиотека или фреймворк, подключаемый через CocoaPods, менеджер зависимостей в iOS. Он автоматически загружает, компилирует и подключает сторонние библиотеки к проекту.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from easyoffer
Новая фича на easyoffer – Автоотлики
Вы автоматически откликаетесь на подходящие вам вакансии. Попробуйте её бесплатно и начните получать больше предложений о работе.
🚀 Запуск занимаем всего 3 минуты, а экономит очень много времени
🛡 Это безопасно: easyoffer официально одобрен HeadHunter и прошел его модерацию.
🥷🏻 Автоотклик незаметен для рекртера. Автоотклик ничем не отличается от обычного отклика, который вы делаете вручную
Рекрутеры давно используют автоматизацию для поиска кандидатов. Так почему вы должны откликаться вручную?
💡Совет – Добавьте шаблон сопроводительного письма, чтобы откликаться на большее количество вакансий (на некоторые вакансии нельзя откликнуться без сопроводительного)
Попробовать бесплатно → https://easyoffer.ru/autoapply
Вы автоматически откликаетесь на подходящие вам вакансии. Попробуйте её бесплатно и начните получать больше предложений о работе.
🚀 Запуск занимаем всего 3 минуты, а экономит очень много времени
🛡 Это безопасно: easyoffer официально одобрен HeadHunter и прошел его модерацию.
🥷🏻 Автоотклик незаметен для рекртера. Автоотклик ничем не отличается от обычного отклика, который вы делаете вручную
Рекрутеры давно используют автоматизацию для поиска кандидатов. Так почему вы должны откликаться вручную?
💡Совет – Добавьте шаблон сопроводительного письма, чтобы откликаться на большее количество вакансий (на некоторые вакансии нельзя откликнуться без сопроводительного)
Попробовать бесплатно → https://easyoffer.ru/autoapply
Это высокоуровневый механизм синхронизации, который объединяет взаимное исключение (mutex) и условные переменные (condition variables) для управления доступом к объектам в многопоточной среде.
Только один поток может выполнить защищенный блок кода в любой момент времени.
Позволяют потокам ожидать определенных условий, а другим потокам уведомлять их о наступлении этих условий.
class ThreadSafeClass {
private var internalState = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")
func increment() {
queue.sync {
internalState += 1
}
}
func getState() -> Int {
return queue.sync {
internalState
}
}
}С
NSLockclass ThreadSafeClass {
private var internalState = 0
private let lock = NSLock()
func increment() {
lock.lock()
internalState += 1
lock.unlock()
}
func getState() -> Int {
lock.lock()
let state = internalState
lock.unlock()
return state
}
}С
objc_sync_enter и objc_sync_exitclass ThreadSafeClass: NSObject {
private var internalState = 0
func increment() {
objc_sync_enter(self)
internalState += 1
objc_sync_exit(self)
}
func getState() -> Int {
objc_sync_enter(self)
let state = internalState
objc_sync_exit(self)
return state
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Один из самых простых и гибких способов реализовать абстракцию — это использование протоколов (protocols).
Протоколы определяют набор требований (свойств, методов), не реализуя их, и позволяют легко заменять конкретные реализации в коде. Это даёт возможность:
- Заменять реализацию (например, для тестирования).
- Разделять ответственность.
- Поддерживать слабую связность компонентов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это механизм в iOS и macOS для обмена сообщениями между различными частями приложения. Он позволяет объектам отправлять и получать уведомления без необходимости напрямую ссылаться друг на друга, что способствует более гибкому и модульному дизайну.
Любой объект может отправить уведомление с помощью Notification Center. Уведомления идентифицируются по имени (
Notification.Name). Можно передать дополнительную информацию в виде словаря (userInfo).NotificationCenter.default.post(name: .myNotification, object: nil)
Объекты могут регистрироваться для получения уведомлений с определенным именем. Для обработки уведомлений используется метод, который будет вызван при получении уведомления.
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: .myNotification, object: nil)
@objc func handleNotification(notification: Notification) {
print("Received notification")
}
Важно удалять наблюдателей, когда они больше не нужны, чтобы избежать утечек памяти. Обычно это делается в методе
deinit или перед уничтожением объекта.NotificationCenter.default.removeObserver(self, name: .myNotification, object: nil)
Объекты не нужно напрямую ссылаться друг на друга, что улучшает модульность кода.
Позволяет легко организовать обмен сообщениями между различными частями приложения.
Уведомления могут использоваться многими объектами, что облегчает реализацию функций, таких как обновление интерфейса или реагирование на события.
Когда данные изменяются, можно отправить уведомление для обновления пользовательского интерфейса.
NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
Например, можно подписаться на уведомление о смене состояния сети.
NotificationCenter.default.addObserver(self, selector: #selector(handleNetworkChange), name: .reachabilityChanged, object: nil)
Различные модули приложения могут общаться друг с другом через Notification Center, не создавая сильных зависимостей.
NotificationCenter.default.post(name: .userDidLogin, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: .userDidLogin, object: nil)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Если вы хотите задать отступы (margins, padding) для
UIView в жизненном цикле UIViewController, то важно выбрать правильный момент, когда размеры view уже определены. class MyViewController: UIViewController {
let myView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
myView.backgroundColor = .red
view.addSubview(myView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Установка отступов (margins)
myView.frame = view.bounds.insetBy(dx: 20, dy: 50)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Они определяют, насколько элемент предпочитает сохранять свой минимальный размер. Чем выше значение, тем меньше вероятность, что элемент растянется больше, чем необходимо его контенту.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Слабые ссылки (weak references) играют важную роль в управлении памятью, особенно когда нужно предотвратить циклы сильных ссылок (retain cycles) и утечки памяти.
Циклы сильных ссылок возникают, когда два объекта держат сильные ссылки друг на друга, что препятствует их освобождению из памяти. Слабые ссылки разрывают этот цикл, позволяя одному из объектов освобождаться.
class Person {
var name: String
weak var friend: Person?
init(name: String) {
self.name = name
}
}
var alice: Person? = Person(name: "Alice")
var bob: Person? = Person(name: "Bob")
alice?.friend = bob
bob?.friend = alice
alice = nil // Теперь объекты могут быть освобождены
bob = nil Утечки памяти происходят, когда объекты, которые больше не нужны, не освобождаются из памяти. Слабые ссылки помогают избежать этих утечек, обеспечивая правильное освобождение памяти. Делегаты часто объявляются как слабые ссылки, чтобы избежать утечек памяти.
protocol TaskDelegate: AnyObject {
func taskDidFinish()
}
class Task {
weak var delegate: TaskDelegate?
func complete() {
delegate?.taskDidFinish()
}
}
class ViewController: TaskDelegate {
var task = Task()
init() {
task.delegate = self
}
func taskDidFinish() {
print("Task finished")
}
} Слабые ссылки удобны для временных зависимостей, когда объект не должен удерживаться в памяти, если нет других сильных ссылок. Использование слабых ссылок для временных объектов.
class Cache {
weak var temporaryObject: SomeClass?
}
class SomeClass {
// Код класса
}
var cache = Cache()
var object = SomeClass()
cache.temporaryObject = object
object = SomeClass() // Старый объект удаляется, так как на него нет сильных ссылок Основное преимущество слабых ссылок заключается в их способности разрывать циклы ссылок, предотвращая утечки памяти.
Слабые ссылки позволяют объектам освобождаться из памяти, когда на них больше нет сильных ссылок, что улучшает управление ресурсами.
Использование слабых ссылок обеспечивает более гибкое и безопасное управление зависимостями между объектами.
Необходимо учитывать, что слабые ссылки могут стать nil в любой момент, поэтому требуется дополнительная проверка.
Требуется хорошее понимание жизненного цикла объектов и управления памятью, чтобы правильно использовать слабые ссылки.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
– Обычный public класс может использоваться в другом модуле, но не может быть унаследован.
– open класс можно наследовать и переопределять даже в других модулях.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Если все переменные в коде сделать
weak, объекты могут мгновенно удаляться из памяти, потому что никто не будет владеть ими (strong reference). -
weak создает слабую ссылку – объект не увеличивает счетчик ссылок (retain count). - Если нет других (strong) ссылок на объект, он удаляется (ARC освобождает память).
-
weak переменные всегда являются Optional, потому что объект может стать nil в любой момент. class Person {
weak var name: String? // ❌ Ошибка! Строки – это value type, weak нельзя
}Проблема, если
weak используется вездеclass Car {
weak var model: String? // ❌ Ошибка (value type)
weak var owner: Person? // ⚠️ Будет nil, если нет других strong ссылок
}
class Person {
var car: Car?
}
var person: Person? = Person()
person?.car = Car()
person?.car?.owner = person // ❌ `owner` - weak, объект сразу удалится
print(person?.car?.owner) // nil, объект Person уничтоженНапример, между
delegate и ViewController protocol SomeDelegate: AnyObject {
func doSomething()
}
class ViewController {
weak var delegate: SomeDelegate? // ✅ Prevent retain cycle
}Например, ячейки в
UITableView не должны владеть ViewController.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1. Удобен для координации задач, выполняемых параллельно.
2. Используется для уведомления, когда все задачи завершены.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM