Anonymous Quiz
28%
Deep Copy
10%
Shallow Copy
25%
Copy Constructor
38%
Value Semantics
🤔12👾3
actor — это новый тип, введённый в Swift 5.5, который предназначен для упрощения и повышения безопасности многопоточного программирования. actor позволяет инкапсулировать состояние и обеспечивает синхронизацию доступа к этому состоянию, предотвращая состояния гонки (race conditions).Все свойства и методы
actor защищены и могут быть безопасно изменены только внутри самого actor. Внешний доступ к состоянию actor происходит через асинхронные вызовы, обеспечивая безопасную синхронизацию.actor автоматически синхронизирует доступ к своим данным, что исключает состояния гонки и делает код безопасным для многопоточного использования.Вызов методов
actor и доступ к его свойствам извне осуществляется через асинхронные функции с использованием await.Пример использования
actoractor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
let counter = Counter()
Task {
await counter.increment()
let value = await counter.getValue()
print("Counter value: \(value)")
}Внутреннее состояние
actor доступно только через методы и свойства самого actor. Прямой доступ к свойствам извне невозможен.Все взаимодействия с
actor из других контекстов требуют использования await, что обеспечивает синхронизацию доступа.Использование
actor упрощает код и делает его более безопасным по сравнению с ручным использованием Grand Central Dispatch (GCD) или мьютексов для синхронизации. actor автоматически управляет синхронизацией, устраняя необходимость в ручном управлении очередями и блокировкамиclass Counter {
private var value = 0
private let queue = DispatchQueue(label: "com.example.counter")
func increment() {
queue.sync {
value += 1
}
}
func getValue() -> Int {
return queue.sync {
return value
}
}
}class Counter {
private var value = 0
private let lock = NSLock()
func increment() {
lock.lock()
value += 1
lock.unlock()
}
func getValue() -> Int {
lock.lock()
let currentValue = value
lock.unlock()
return currentValue
}
}async и await.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥4
Anonymous Quiz
17%
fileprivate
44%
private
17%
internal
21%
extension
🤔11🤯3👍1😁1
В Swift структуры являются типами значений (value types), что означает, что они по умолчанию копируются при передаче или присвоении. Однако копирование структуры происходит только при изменении (copy-on-write) её состояния, чтобы оптимизировать производительность и снизить избыточные копии. Рассмотрим подробнее, как это работает.
struct MyStruct {
var value: Int
}
var a = MyStruct(value: 10)
var b = a // Копия создается, но фактически это происходит "лениво"
b.value = 20 // В этот момент происходит копирование, так как структура изменяется
print(a.value) // Output: 10
print(b.value) // Output: 20a создается и инициализируется значением 10.b присваивается значение a. На этом этапе копия не создается, так как копирование структур в Swift оптимизировано и происходит лениво.value структуры b, происходит копирование, чтобы изменить b без изменения a.Это оптимизация, при которой фактическое копирование структуры происходит только тогда, когда необходимо изменить её содержимое. До тех пор, пока структура не изменяется, обе переменные будут ссылаться на одни и те же данные.
struct LargeStruct {
var data = [Int](repeating: 0, count: 1000)
}
var x = LargeStruct()
var y = x // Копия не создается сразу
y.data[0] = 1 // Копирование происходит здесь, при изменении
print(x.data[0]) // Output: 0
print(y.data[0]) // Output: 1x присваивается структура LargeStruct, содержащая массив данных.y присваивается значение x. На этом этапе копия не создается.data в структуре y, происходит копирование данных, чтобы x и y имели свои собственные копии массива.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Anonymous Quiz
15%
Delegation
26%
Adapter
44%
Protocol Extension
16%
Type Erasure
😁4
В Swift структуры не поддерживают множественное наследование, так как наследование вообще не применяется к структурам. Наследование — это механизм, доступный только для классов. Структуры и перечисления (enums) в Swift могут принимать протоколы, что позволяет им реализовывать множественное поведение, но не наследовать реализацию.
Протоколы в Swift позволяют описывать интерфейсы и требования, которые должны выполнять структуры, классы или перечисления. Это основной способ добиться множественного поведения.
protocol Describable {
var description: String { get }
}
protocol Identifiable {
var id: Int { get }
}
struct User: Describable, Identifiable {
var description: String
var id: Int
}Композиция предполагает создание сложных типов путем комбинирования более простых типов. Это позволяет гибко создавать функциональные структуры без необходимости наследования.
struct Address {
var street: String
var city: String
}
struct Person {
var name: String
var address: Address
}
let address = Address(street: "123 Main St", city: "New York")
let person = Person(name: "John", address: address)Расширения позволяют добавлять методы, свойства и функциональность к существующим типам без необходимости изменять исходный код этих типов.
protocol Greetable {
func greet()
}
extension Greetable {
func greet() {
print("Hello!")
}
}
struct User: Greetable {
var name: String
}
let user = User(name: "Alice")
user.greet() // Output: Hello!Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Anonymous Quiz
14%
Clonable
34%
Copying
47%
NSCopying
6%
CopyProtocol
❤1
Это специальный метод, который вызывается непосредственно перед тем, как объект класса освобождается из памяти. В Swift деинициализаторы используются для выполнения завершающих операций, таких как освобождение ресурсов или выполнение финальной очистки.
Деинициализаторы объявляются с помощью ключевого слова
deinit. Классы могут иметь только один деинициализатор. Деинициализаторы не принимают аргументов и не возвращают значений.Деинициализатор вызывается автоматически системой управления памятью Swift (ARC) перед тем, как объект класса будет освобожден из памяти. Этот метод не может быть вызван явно.
Деинициализаторы используются для выполнения завершающих операций, таких как освобождение ресурсов, закрытие файлов, остановка таймеров и отмена сетевых запросов.
class Resource {
init() {
print("Resource initialized")
}
deinit {
print("Resource deinitialized")
}
}
var resource: Resource? = Resource() // Output: "Resource initialized"
resource = nil // Output: "Resource deinitialized"В этом примере:
Класс
Resource имеет деинициализатор, который выводит сообщение при освобождении объекта. Переменная resource сначала инициализируется экземпляром Resource, что приводит к вызову инициализатора. Когда переменной resource присваивается nil, объект освобождается, и вызывается деинициализатор.Деинициализаторы часто используются для освобождения ресурсов, таких как файлы или сетевые соединения.
class FileHandler {
let file: File
init(file: File) {
self.file = file
// Открытие файла
}
deinit {
// Закрытие файла
print("Файл закрыт")
}
}Если класс использует таймер, деинициализатор может быть использован для его остановки.
class TimerClass {
var timer: Timer?
init() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
print("Таймер работает")
}
}
deinit {
timer?.invalidate()
print("Таймер остановлен")
}
}Если класс выполняет сетевые запросы, деинициализатор может быть использован для их отмены.
class NetworkManager {
var dataTask: URLSessionDataTask?
func fetchData() {
let url = URL(string: "https://example.com")!
dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
// Обработка ответа
}
dataTask?.resume()
}
deinit {
dataTask?.cancel()
print("Сетевой запрос отменён")
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Anonymous Quiz
39%
OperatorProtocol
33%
CustomOperator
19%
ExpressibleByOperator
9%
ExpressibleByIntegerLiteral
👾3🤔1
Ретейн-релиз (retain-release) — это модель управления памятью, которая использовалась в Objective-C до появления автоматического подсчета ссылок (Automatic Reference Counting, ARC). В этой модели разработчик вручную контролирует время жизни объектов, используя методы
retain, release и autorelease. В Swift эта модель заменена ARC, но понимание ретейн-релиз важно для работы с устаревшим кодом и интеграции с Objective-C.Каждый объект в памяти имеет счётчик ссылок, который отслеживает количество сильных ссылок на этот объект. Когда создается новая сильная ссылка на объект, счётчик ссылок увеличивается. Когда сильная ссылка удаляется, счётчик ссылок уменьшается.
retain: Увеличивает счётчик ссылок на объект.release: Уменьшает счётчик ссылок на объект. Когда счётчик достигает нуля, объект освобождается из памяти.autorelease: Помещает объект в autorelease pool, который отправляет сообщение release объектам при спуске (drain) пула.Autorelease Pool
Это механизм для управления временными объектами, который автоматически освобождает их память после завершения текущего цикла событий. Autorelease pool используется для временного хранения объектов, которым нужно отправить сообщение
release позже.@autoreleasepool {
NSString *tempString = [[NSString alloc] initWithFormat:@"Hello, %@", @"World"];
[tempString autorelease];
// tempString будет автоматически освобождена в конце блока autoreleasepool
}В Swift управление памятью автоматизировано с помощью ARC, который выполняет те же действия, что и ретейн-релиз, но автоматически. Разработчик больше не должен явно вызывать
retain и release, это делает компилятор.class MyClass {
var value: Int
init(value: Int) {
self.value = value
print("Object initialized")
}
deinit {
print("Object deinitialized")
}
}
var obj: MyClass? = MyClass(value: 10) // Счётчик ссылок: 1
obj = nil // Счётчик ссылок: 0, объект освобождается из памятиСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Anonymous Quiz
3%
sealed
90%
final
4%
static
4%
private
❤1
Unowned ссылки в Swift не увеличивают счётчик ссылок на объект. Это означает, что unowned ссылка не удерживает объект в памяти, и объект может быть освобожден, даже если на него существуют unowned ссылки.Unowned ссылки не увеличивают счётчик ссылок на объект, к которому они относятся. Это позволяет избежать циклических зависимостей, но требует, чтобы объект, на который ссылается unowned ссылка, существовал на протяжении всего времени жизни ссылки.Unowned ссылки полезны, когда объект, на который ссылаются, гарантированно будет существовать до тех пор, пока существует сама ссылка. В отличие от слабых ссылок (weak), unowned ссылки не обнуляются автоматически, когда объект освобождается. Это означает, что использование unowned ссылки на освобожденный объект приведет к ошибке времени выполнения (runtime error).class Customer {
var name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) is being deinitialized")
}
}
class CreditCard {
var number: Int
unowned let customer: Customer
init(number: Int, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Card #\(number) is being deinitialized")
}
}
var john: Customer? = Customer(name: "John")
john!.card = CreditCard(number: 1234, customer: john!)
john = nil
// Output:
// John is being deinitialized
// Card #1234 is being deinitializedCustomer и CreditCard ссылаются друг на друга. Customer имеет сильную ссылку на CreditCard, а CreditCard имеет unowned ссылку на Customer. Когда объект john устанавливается в nil, оба объекта освобождаются из памяти.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Anonymous Quiz
61%
Extensions
23%
Protocols
13%
Generics
3%
Inheritance
👍1
Модификатор
volatile в программировании используется для указания компилятору, что значение переменной может измениться в любое время, вне зависимости от оптимизаций, которые он может выполнять. Это полезно в многопоточных программах и при работе с аппаратным обеспечением.В языке Swift нет прямого аналога модификатора
volatile, который имеется в C или C++. Однако, его цель можно объяснить и понять через использование других инструментов и подходов, таких как атомарные операции и синхронизация, которые обеспечивают корректное поведение многопоточных программ.Здесь переменная
flag объявлена с модификатором volatile, чтобы компилятор не оптимизировал чтение её значения внутри цикла, предполагая, что оно не изменится. Без volatile, компилятор мог бы оптимизировать код так, что цикл стал бы бесконечным.volatile int flag = 0;
void someFunction() {
while (flag == 0) {
// ждем изменения флага
}
// флаг изменен, продолжаем выполнение
}
Для достижения аналогичного эффекта в Swift можно использовать атомарные операции или объекты синхронизации, чтобы управлять доступом к переменным из разных потоков. Здесь используется атомарная переменная
ManagedAtomic, чтобы гарантировать корректное чтение и запись флага в многопоточном окружении. В Swift можно использовать библиотеку Atomic из Swift Atomics для безопасного управления доступом к переменным: import Atomics
class ThreadSafeFlag {
private var flag = ManagedAtomic(0)
func setFlag(_ value: Int) {
flag.store(value, ordering: .relaxed)
}
func waitForFlag() {
while flag.load(ordering: .relaxed) == 0 {
// ждем изменения флага
}
// флаг изменен, продолжаем выполнение
}
}
Здесь
DispatchQueue гарантирует, что чтение и запись флага будут выполнены атомарно. Другой подход - использование DispatchQueue для управления доступом к ресурсу: class ThreadSafeFlag {
private var flag = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")
func setFlag(_ value: Int) {
queue.sync {
flag = value
}
}
func waitForFlag() {
var currentFlag = 0
while true {
queue.sync {
currentFlag = flag
}
if currentFlag != 0 {
break
}
}
// флаг изменен, продолжаем выполнение
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
Anonymous Quiz
3%
Garbage Collection
1%
Memory Pool
3%
Reference Counting
93%
Automatic Reference Counting (ARC)
❤1
Weak и Strong ссылки - это ключевые концепции управления памятью в Swift, которые используются для предотвращения циклов удержания (retain cycles) и для правильного управления временем жизни объектов. Однако, термин Anound не является стандартным термином в Swift или других языках программирования. Сильная ссылка (по умолчанию) увеличивает счетчик ссылок (reference count) объекта на единицу. Объект, на который имеются сильные ссылки, не будет освобожден до тех пор, пока хотя бы одна сильная ссылка на него существует.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
var person1: Person? = Person(name: "John")
var person2 = person1 // Strong reference
person1 = nil
// person2 все еще удерживает объект, объект не будет освобожденСлабая ссылка не увеличивает счетчик ссылок объекта. Слабые ссылки всегда объявляются как опциональные (optional) типа, так как объект может быть освобожден, и слабая ссылка станет
nil. class Person {
var name: String
init(name: String) {
self.name = name
}
}
class Company {
var employee: Person?
}
var person: Person? = Person(name: "John")
var company = Company()
company.employee = person // Strong reference
weak var weakPerson = person // Weak reference
person = nil
// weakPerson становится nil, объект освобожденНевладеющая ссылка, как и слабая, не увеличивает счетчик ссылок объекта. Однако, в отличие от слабой ссылки, невладеющая ссылка не является опциональной. Она предполагает, что объект всегда будет существовать во время использования ссылки. Использование невладеющей ссылки на уже освобожденный объект приведет к ошибке выполнения.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
class Company {
unowned var employee: Person
init(employee: Person) {
self.employee = employee
}
}
var person: Person? = Person(name: "John")
var company = Company(employee: person!) // Unowned reference
person = nil
// Доступ к company.employee приведет к ошибке выполнения, так как person уже освобожденСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯3👾3
Anonymous Quiz
92%
async
5%
await
1%
defer
2%
dispatch
❤1
Сайт
UITableView (Table View) в iOS используется для отображения списков данных в виде таблицы. Это один из наиболее часто используемых компонентов пользовательского интерфейса в приложениях iOS, так как позволяет организовывать и представлять большие объемы информации в удобном для пользователя формате.UITableView позволяет отображать большие списки данных, которые могут быть прокручиваемыми. Это особенно полезно для отображения динамически загружаемых данных, таких как ленты новостей, списки контактов, каталоги товаров и т.д.UITableView предоставляет методы для добавления, удаления и обновления строк данных, что упрощает управление динамическими списками. Он также поддерживает анимацию изменений, что улучшает пользовательский опыт.UITableView позволяет использовать кастомные ячейки для отображения данных, предоставляя гибкость в создании пользовательского интерфейса. Это можно сделать путем создания пользовательских классов ячеек и настройки их внешнего вида.UITableView поддерживает разделение данных на секции с заголовками и подзаголовками, что упрощает организацию и навигацию по спискам данных.Основной элемент, используемый для отображения строки данных. Ячейки могут быть стандартными или кастомными.
UITableView может содержать несколько секций, каждая из которых может содержать несколько строк. Секции могут иметь заголовки и подзаголовки.UITableView предоставляет методы для обновления данных, такие как reloadData(), которые перезагружают всю таблицу, и методы для обновления отдельных строк или секций с анимацией.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5🤔3❤2🤯1
Anonymous Quiz
6%
finally
59%
defer
3%
ensure
32%
closure
❤2
Эскейсы (замыкания) могут захватывать и удерживать контекст, в котором они созданы, что может быть как хорошо, так и плохо в зависимости от ситуации.
Замыкания могут захватывать переменные и константы из окружающего контекста, что делает их мощным инструментом для создания компактного и выразительного кода.
func makeIncrementer(incrementAmount: Int) -> () -> Int {
var total = 0
let incrementer: () -> Int = {
total += incrementAmount
return total
}
return incrementer
}
let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo()) // 2
print(incrementByTwo()) // 4Замыкания позволяют сохранить состояние между вызовами, что может быть полезно в некоторых сценариях, как показано в примере выше.
Захват контекста позволяет создавать функции высшего порядка и применять функциональные подходы, такие как каррирование и композиция функций.
Замыкания могут захватывать ссылки на объекты, что приводит к циклам удержания, когда объекты удерживают друг друга и никогда не освобождаются. В этом примере, если не использовать
weak или unowned ссылки, замыкание захватит self, создавая цикл удержания.class MyClass {
var value: Int = 0
lazy var incrementer: () -> Void = {
self.value += 1
}
}
let instance = MyClass()
instance.incrementer()Замыкания, захватывающие контекст, могут усложнять отладку и понимание кода, особенно когда контекст изменяется или когда замыкание выполняется асинхронно.
Если замыкание захватывает изменяемое состояние, это может привести к трудноуловимым ошибкам, связанным с изменением состояния в неожиданных местах.
Для предотвращения циклов удержания используйте слабые или невладеющие ссылки на
self внутри замыканий. class MyClass {
var value: Int = 0
lazy var incrementer: () -> Void = { [weak self] in
self?.value += 1
}
} Захватывайте только те переменные, которые действительно необходимы в замыкании.
Используйте инструменты отладки и анализаторы утечек памяти, такие как Xcode Instruments, чтобы выявлять и исправлять потенциальные проблемы.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1