Используется в замыканиях (closures) для управления тем, как замыкание захватывает переменные и константы из окружающего контекста. Могут захватывать и хранить ссылки на любые константы и переменные из контекста, в котором они определены. Это удобно, но может привести к сильным ссылочным циклам и утечкам памяти, если замыкание захватывает
self или другие экземпляры класса.Предоставляет способ определить правила захвата переменных в замыкании. Она задаётся в начале замыкания и позволяет избежать нежелательных сильных ссылок, особенно при работе с
self в методах класса, что очень важно для предотвращения утечек памяти в приложениях.Синтаксис Capture List
{ [capture rule] (parameters) -> return type in
// Код замыкания
}Пример с простым замыканием
var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure() // Выведет "0 10"
Использование Capture List для предотвращения сильных ссылочных циклов
class MyClass {
var property = "Property"
func doSomething() {
let closure = { [weak self] in
print(self?.property ?? "нет self")
}
closure()
}
deinit {
print("MyClass экземпляр был деинициализирован")
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Термин "диспетчеризация" часто используется для описания механизма, посредством которого вызывается метод или функция в ответ на вызов. В контексте ООП, особенно в языках с поддержкой полиморфизма, диспетчеризация может быть статической (ранней) или динамической (поздней).
Использует компиляцию времени компиляции для определения того, какой метод будет вызван. Это означает, что компилятор определяет адрес вызываемого метода на этапе компиляции, и этот адрес не изменяется во время выполнения программы.
В языках, таких как C и Swift (при использовании
final классов или структур), методы, известные во время компиляции, могут быть вызваны без дополнительной нагрузки, связанной с поиском в таблице виртуальных функций.Используется в языках программирования, поддерживающих полиморфизм и наследование, и означает, что метод, который будет вызван, определяется во время выполнения. Это позволяет объектам различных классов отвечать на одни и те же сообщения (вызовы методов), каждый по-своему.
Таблица виртуальных методов (VMT): В объектно-ориентированных языках, таких как C++ или Java, каждый класс с виртуальными методами имеет таблицу виртуальных методов. Эта таблица содержит адреса всех виртуальных методов, которые могут быть вызваны для объекта данного класса. Поиск по таблице: Во время выполнения, когда вызывается метод, производится поиск соответствующего метода в таблице VMT, и используется адрес, найденный в таблице, что вносит задержку по сравнению со статической диспетчеризацией.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
- Слабые ссылки (weak): не увеличивают счётчик ссылок, используются для предотвращения циклических зависимостей.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её.
Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами.
Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие.
Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения.
Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова
final. Если метод, свойство или индексатор объявлен как final, то он не может быть переопределён в подклассе.class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// Этот метод будет переопределен в подклассах, если необходимо
}
}
class Bicycle: Vehicle {
var hasBasket = false
}
class Car: Vehicle {
var gear = 1
final func drive() {
print("Car is moving")
}
override func makeNoise() {
print("Vroom!")
}
}Подклассы могут вызывать методы своего суперкласса с помощью ключевого слова
super. Это позволяет подклассам расширять, а не заменять поведение суперкласса.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Обычно имеют в виду различия между использованием стека вызовов (память стека) и кучи (heap) в контексте управления памятью в программировании. Эти два типа памяти имеют разные способы выделения и освобождения памяти, каждый со своими преимуществами и недостатками.
Память в стеке выделяется и освобождается по очень простому и быстрому принципу: LIFO (Last In, First Out). Это означает, что для выделения памяти достаточно переместить указатель стека вверх (при добавлении данных) или вниз (при удалении данных). Этот процесс почти мгновенен и не требует дополнительных вычислений.
В куче память выделяется динамически, что требует управления доступными блоками памяти. Аллокатор памяти должен найти достаточно большой свободный блок, что может занять значительное время, особенно если память фрагментирована. Также освобождение памяти в куче требует более сложной обработки, включая возможную дефрагментацию.
Доступ к данным в стеке очень быстрый, потому что данные всегда добавляются и удаляются с "вершины" стека, где находится указатель стека. Это делает доступ к текущим локальным переменным очень быстрым и предсказуемым. Доступ к данным в куче может быть менее эффективным, поскольку данные могут быть разбросаны по разным частям памяти. Кроме того, дополнительное время требуется для поиска и управления блоками памяти.
Его память автоматически очищается при выходе из области видимости, что упрощает управление памятью и снижает риск утечек памяти. Память, выделенная в куче, остаётся занятой до тех пор, пока явно не будет освобождена. Это увеличивает риск утечек памяти, если разработчик забудет освободить память.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
- Аллокацию памяти.
- Освобождение через сборщик мусора (в Java, Swift) или вручную (в C++).
- Компактирование для предотвращения фрагментации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2🤯2👍1
Это абстрактная структура данных, работающая по принципу 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
❤4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В iOS-приложениях можно создавать анимации несколькими способами.
Самый простой способ анимации представлений (views) в iOS - это использование метода
UIView.animate. Вот пример кода, который изменяет положение и прозрачность представления за 1 секунду:UIView.animate(withDuration: 1.0) {
myView.frame.origin.y += 100
myView.alpha = 0.5
}Для более сложных анимаций можно использовать Core Animation, например,
CABasicAnimation. Вот пример анимации изменения позиции слоя (layer):let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: CGPoint(x: 50, y: 50))
animation.toValue = NSValue(cgPoint: CGPoint(x: 150, y: 150))
animation.duration = 1.0
myView.layer.add(animation, forKey: "positionAnimation")
Этот класс предоставляет более детальный контроль над анимациями. Его можно использовать для создания и управления анимациями в реальном времени:
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut) {
myView.frame.origin.y += 100
myView.alpha = 0.5
}
animator.startAnimation()Для создания реалистичных анимаций с пружинным эффектом можно использовать метод
UIView.animate с параметрами пружинного демпфирования:UIView.animate(withDuration: 1.0,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 0.5,
options: [],
animations: {
myView.frame.origin.y += 100
myView.alpha = 0.5
}, completion: nil)
Для анимации переходов между экранами используется
UIViewControllerAnimatedTransitioning. Это требует реализации методов протокола UIViewControllerAnimatedTransitioning:class CustomTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromView = transitionContext.view(forKey: .from),
let toView = transitionContext.view(forKey: .to) else { return }
transitionContext.containerView.addSubview(toView)
toView.alpha = 0.0
UIView.animate(withDuration: 0.5, animations: {
toView.alpha = 1.0
}, completion: { finished in
transitionContext.completeTransition(finished)
})
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это ключевое слово, используемое для объявления слабой ссылки (weak reference) на объект, которая не увеличивает счетчик ссылок этого объекта. В отличие от
weak, unowned ссылки никогда не становятся nil, поэтому они используются в тех случаях, когда можно гарантировать, что объект, на который ссылаются, будет существовать так же долго, как и сама ссылка.Например, если один объект никогда не будет существовать дольше другого объекта, и тем самым вы уверены, что ссылка всегда будет действительной.
Чтобы предотвратить циклы сильных ссылок, которые могут привести к утечкам памяти.
``` swift
class Person {
let name: String
var creditCard: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) is being deinitialized")
}
}
class CreditCard {
let number: String
unowned let owner: Person
init(number: String, owner: Person) {
self.number = number
self.owner = owner
}
deinit {
print("CreditCard #\(number) is being deinitialized")
}
}
// Пример использования
var john: Person? = Person(name: "John Appleseed")
john?.creditCard = CreditCard(number: "1234 5678 9012 3456", owner: john!)
john = nil
```
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это метод, который вызывается перед удалением объекта из памяти. В Swift используется метод deinit. Он позволяет выполнять действия, такие как освобождение ресурсов или закрытие соединений, когда объект больше не нужен.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это структура данных, которая работает по принципу "первым пришел - первым ушел" (FIFO, First In, First Out). Это значит, что элементы добавляются в конец очереди и извлекаются из начала очереди.
Вставка элемента в конец очереди.
Удаление элемента из начала очереди.
Просмотр элемента в начале очереди без его удаления.
Проверка, содержит ли очередь элементы.
Очереди часто используются в задачах, где порядок обработки элементов важен.
Управление задачами в системах реального времени.
Обработка запросов в сетевых приложениях.
Имплементация алгоритмов обхода графов (например, поиск в ширину).
struct Queue<T> {
private var elements: [T] = []
// Добавление элемента в конец очереди
mutating func enqueue(_ element: T) {
elements.append(element)
}
// Удаление элемента из начала очереди
mutating func dequeue() -> T? {
return isEmpty ? nil : elements.removeFirst()
}
// Просмотр элемента в начале очереди
func peek() -> T? {
return elements.first
}
// Проверка на пустоту
var isEmpty: Bool {
return elements.isEmpty
}
}
// Пример использования
var queue = Queue<Int>()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
print(queue.dequeue() ?? "Queue is empty") // Вывод: 1
print(queue.peek() ?? "Queue is empty") // Вывод: 2GCD (Grand Central Dispatch) использует очереди для управления многозадачностью. Например,
DispatchQueue.main.async добавляет задачи в очередь для выполнения на главном потоке:DispatchQueue.main.async {
// Код выполняется на главном потоке
}Используются для управления и упорядочивания выполнения множества
Operation объектов:let queue = OperationQueue()
queue.addOperation {
print("Operation 1")
}
queue.addOperation {
print("Operation 2")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1. Retain: увеличивает счетчик ссылок объекта, указывая, что объект используется.
2. Release: уменьшает счетчик ссылок. Когда счетчик достигает нуля, объект освобождается из памяти.
Эта модель широко использовалась в Objective-C до появления ARC (Automatic Reference Counting).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В Swift, помимо структур (structs), к типам-значениям (value types) также относятся перечисления (enums) и кортежи (tuples).
Структуры в Swift являются типами-значениями. Когда вы создаете копию структуры, вы получаете новый экземпляр со своим собственным набором данных. Изменения в одном экземпляре не влияют на другие экземпляры.
struct Point {
var x: Int
var y: Int
}
var point1 = Point(x: 0, y: 0)
var point2 = point1
point2.x = 10
print(point1.x) // Вывод: 0
print(point2.x) // Вывод: 10Перечисления также являются типами-значениями. При копировании экземпляра перечисления создается новый экземпляр с тем же значением.
enum CompassDirection {
case north, south, east, west
}
var direction1 = CompassDirection.north
var direction2 = direction1
direction2 = .south
print(direction1) // Вывод: north
print(direction2) // Вывод: southКортежи в Swift тоже являются типами-значениями. Кортежи позволяют объединять несколько значений в одну составную единицу. При копировании кортежа создается новый кортеж с теми же значениями.
var tuple1 = (a: 1, b: 2)
var tuple2 = tuple1
tuple2.a = 3
print(tuple1.a) // Вывод: 1
print(tuple2.a) // Вывод: 3
Типы-значения копируются при передаче и присваивании, а ссылочные типы (классы и замыкания) передаются по ссылке. Это важное различие влияет на то, как изменяются данные при передаче между переменными и функциями.
Для сравнения, классы являются ссылочными типами (reference types). При копировании экземпляра класса копируется не сам объект, а ссылка на него. Поэтому изменения в одном экземпляре отражаются на всех его копиях.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
var person1 = Person(name: "John")
var person2 = person1
person2.name = "Doe"
print(person1.name) // Вывод: Doe
print(person2.name) // Вывод: DoeСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Нет, у unowned ссылок нет собственного счетчика ссылок. Они не увеличивают счетчик объекта, к которому ссылаются. Это означает, что если объект удален из памяти, попытка обращения к unowned ссылке вызовет runtime-ошибку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
В Swift и других языках программирования существует множество структур данных, каждая из которых предназначена для эффективного хранения, организации и управления данными.
Это упорядоченные коллекции элементов, которые хранятся в непрерывной области памяти. Массивы позволяют быстро получать доступ к элементам по индексу.
var numbers: [Int] = [1, 2, 3, 4, 5]
print(numbers[2]) // Вывод: 3
Это коллекции пар "ключ-значение", которые позволяют быстро находить значения по ключу. Ключи в словаре должны быть уникальными.
var capitalCities: [String: String] = ["France": "Paris", "Japan": "Tokyo"]
print(capitalCities["France"]!) // Вывод: Paris
Это неупорядоченные коллекции уникальных элементов. Они полезны, когда необходимо проверить наличие элемента или выполнить операции над множествами, такие как объединение или пересечение.
var uniqueNumbers: Set<Int> = [1, 2, 3, 4, 5, 1]
print(uniqueNumbers) // Вывод: [5, 2, 3, 1, 4]
Это последовательности элементов, где каждый элемент содержит ссылку на следующий элемент. Связные списки могут быть односвязными (только вперед) или двусвязными (вперед и назад).
class ListNode {
var value: Int
var next: ListNode?
init(value: Int) {
self.value = value
}
}
let head = ListNode(value: 1)
head.next = ListNode(value: 2)
head.next?.next = ListNode(value: 3)Это структура данных, работающая по принципу "последним пришел - первым ушел" (LIFO, Last In, First Out). Стек поддерживает две основные операции: добавление (push) и удаление (pop) элемента.
var stack: [Int] = []
stack.append(1) // push
stack.append(2)
print(stack.pop()!) // pop, вывод: 2
Это структура данных, работающая по принципу "первым пришел - первым ушел" (FIFO, First In, First Out). Очередь поддерживает операции добавления (enqueue) и удаления (dequeue) элемента.
var queue: [Int] = []
queue.append(1) // enqueue
queue.append(2)
print(queue.removeFirst()) // dequeue, вывод: 1
Это иерархическая структура данных, состоящая из узлов, где каждый узел имеет одно родительское и ноль или более дочерних узлов. Наиболее распространенный тип дерева - бинарное дерево, где каждый узел имеет не более двух потомков.
class TreeNode {
var value: Int
var left: TreeNode?
var right: TreeNode?
init(value: Int) {
self.value = value
}
}
let root = TreeNode(value: 1)
root.left = TreeNode(value: 2)
root.right = TreeNode(value: 3)Это набор узлов (вершин), соединенных ребрами. Графы могут быть направленными или ненаправленными, взвешенными или невзвешенными.
class GraphNode {
var value: Int
var neighbors: [GraphNode] = []
init(value: Int) {
self.value = value
}
}
let node1 = GraphNode(value: 1)
let node2 = GraphNode(value: 2)
let node3 = GraphNode(value: 3)
node1.neighbors = [node2, node3]
node2.neighbors = [node1]
node3.neighbors = [node1]Это структура данных, которая реализует словарь с использованием хеш-функции для быстрого доступа к данным по ключу.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
1. Счетчик ссылок: хранится для каждого объекта.
2. Другие данные: например, слабые ссылки (weak references) или ассоциированные объекты.
Она позволяет эффективно управлять объектами без увеличения их базового размера.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1