#observable #swiftui #deepdive
How SwiftUI Tracks UI Changes With Observable (Behind the Scenes)
На канале у Карин вышло видео про работу
- Что это и для чего
- Понимание работы механизма
- Чуть-чуть глубже взгляд на работу
- Как с этим работать и выводы
Посмотреть можно здесь. Эту функцию и многое другое, интересное и связанное с макросом observable мы рассмотрели в этом воркшопе ещё год назад. А в этом воркшопе я уже делился после опыта на вроде и рассматривали практичную информацию по работе на проде.
Читай подробно про каждый воркшоп внутри. А для тех у кого нет небазовой подписке, хочу поделиться парочкой ссылок из одного воркшопа. Они прям для совсем хардкорщиков, там deep dive самого deep dive и всё это в кубе deep dive для изучения
- Swift Observation from Scratch — Part 1 of 2
- Swift Observation from Scratch — Part 2 of 2
Приятного просмотра и изучения!👋
How SwiftUI Tracks UI Changes With Observable (Behind the Scenes)
На канале у Карин вышло видео про работу
withObservationTracking. Где она рассказала всю необходимую информацию по этой функции.- Что это и для чего
- Понимание работы механизма
- Чуть-чуть глубже взгляд на работу
- Как с этим работать и выводы
Посмотреть можно здесь. Эту функцию и многое другое, интересное и связанное с макросом observable мы рассмотрели в этом воркшопе ещё год назад. А в этом воркшопе я уже делился после опыта на вроде и рассматривали практичную информацию по работе на проде.
Читай подробно про каждый воркшоп внутри. А для тех у кого нет небазовой подписке, хочу поделиться парочкой ссылок из одного воркшопа. Они прям для совсем хардкорщиков, там deep dive самого deep dive и всё это в кубе deep dive для изучения
withObservationTracking- Swift Observation from Scratch — Part 1 of 2
- Swift Observation from Scratch — Part 2 of 2
Приятного просмотра и изучения!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2❤1👍1
A Day in the Life of a SwiftUI View
Chris Eidhof раскрывает mental model SwiftUI, показыя, как наш код превращается в ephemeral view tree и в персистентный render tree — AttributeGraph. Chris подробно объясняет, как @State интегрируется в граф, оптимизирует layout и что происходит при каждом вызове body.
https://www.youtube.com/watch?v=MRY3UCUVv98
https://www.youtube.com/watch?v=MRY3UCUVv98
https://www.youtube.com/watch?v=MRY3UCUVv98
> Текстовая версия доклада
> Похожая статейка в ноушен
> Подробно про AttributeGraph в ноушен
Chris Eidhof раскрывает mental model SwiftUI, показыя, как наш код превращается в ephemeral view tree и в персистентный render tree — AttributeGraph. Chris подробно объясняет, как @State интегрируется в граф, оптимизирует layout и что происходит при каждом вызове body.
https://www.youtube.com/watch?v=MRY3UCUVv98
https://www.youtube.com/watch?v=MRY3UCUVv98
https://www.youtube.com/watch?v=MRY3UCUVv98
> Текстовая версия доклада
> Похожая статейка в ноушен
> Подробно про AttributeGraph в ноушен
YouTube
Chris Eidhof - A Day in the Life of a SwiftUI View
Chris takes us through how a SwiftUI view is rendered, laid out and updated
🔥5❤1👍1
#weak_let #swift #concurrency
Раньше weak можно было только с var, и из-за этого классы и замыкания с такими ссылками не были Sendable, но с принятием этого проползола можно будет объявлять слабые ссылки с let, а не только с var.
Зачем это нужно?
- Убирает лишнюю мутируемость, weak let не мешает проверкам на безопасность в конкурентных контекстах.
- Закрывает брешь в sendability: классы и @Sendable-замыкания с weak let становятся полностью безопасными.
Про мотивацию
1. weak var считался мутируемым, потому что при деинициализации объекта ссылка сбрасывалась в nil.
2. На самом деле это не "мутация" значения, а просто особенность weak ref.
3. Теперь weak let отражает именно эту логику – неизменяемая слабая ссылка, которая по-прежнему может стать nil.
Прочитать подробнее и посмотреть можно здесь: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0481-weak-let.md
Раньше weak можно было только с var, и из-за этого классы и замыкания с такими ссылками не были Sendable, но с принятием этого проползола можно будет объявлять слабые ссылки с let, а не только с var.
Зачем это нужно?
- Убирает лишнюю мутируемость, weak let не мешает проверкам на безопасность в конкурентных контекстах.
- Закрывает брешь в sendability: классы и @Sendable-замыкания с weak let становятся полностью безопасными.
Про мотивацию
1. weak var считался мутируемым, потому что при деинициализации объекта ссылка сбрасывалась в nil.
2. На самом деле это не "мутация" значения, а просто особенность weak ref.
3. Теперь weak let отражает именно эту логику – неизменяемая слабая ссылка, которая по-прежнему может стать nil.
Прочитать подробнее и посмотреть можно здесь: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0481-weak-let.md
GitHub
swift-evolution/proposals/0481-weak-let.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
🔥9👍4🤯1
final class Person {
var name: String
init(name: String) {
self.name = name
}
}
final class ViewModel: ObservableObject {
@Published var person = Person(name: "John")
func changeName() {
person.name = "Alice"
}
}
struct StateObjectInnerView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
Button {
viewModel.changeName()
} label: {
Text(viewModel.person.name)
}
Text("StateObject Demo").padding()
}
}
Ниже будет опрос
Please open Telegram to view this post
VIEW IN TELEGRAM
Вот здесь ответ, под спойлерами.
А прочитать подробнее: можно тут
P.S. Если хотите больше таких небольших задачек на основы работы чего-либо ставьте гхолубя.
А то получается, на собеседованиях спрашивают:
- Кишки
- Алгоритмы
- Рендер лупы
А тут простецкий вопрос вызывает затруднение...И ведь это рабочий use case. Работа с паблишерами, до макроса Observable, выполняется всегда!👋
А прочитать подробнее: можно тут
P.S. Если хотите больше таких небольших задачек на основы работы чего-либо ставьте гхолубя.
А то получается, на собеседованиях спрашивают:
- Кишки
- Алгоритмы
- Рендер лупы
А тут простецкий вопрос вызывает затруднение...И ведь это рабочий use case. Работа с паблишерами, до макроса Observable, выполняется всегда!
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🕊22🔥3👍2
final class ContentViewModel: ObservableObject {
@Published var text = "Hello @StateObject"
init() {
print("ViewModel init")
}
deinit {
print("ViewModel deinit")
}
}
struct ContentView: View {
@StateObject private var viewModel: ContentViewModel
init(viewModel: ContentViewModel) {
_viewModel = StateObject(wrappedValue: viewModel)
print("ContentView init")
}
var body: some View {
Text(viewModel.text)
}
}
struct RootView: View {
@State private var isOn = false
var body: some View {
VStack(spacing: 20) {
ContentView(viewModel: ContentViewModel())
if isOn { Text("is on") }
Button("Trigger") { isOn.toggle() }
}
}
}
Есть ли у этого кода проблема связанная с объявлением StateObject? Опрос ниже
Ответ скрыл под спойлер, а так же прилагаю ссылку в ноушене для детального изучения
🔥5👍4🕊3
Выполнение асинхронных задач в SwiftUI
Начиная с iOS 14 вместо Task {…} в onAppear начинаем юзать встроенный модификатор .task – он сам создаёт и отменяет задачу вместе с жизненным циклом View:
Но зачем так делать?
- Не надо городить Task вручную и переживать об отмене.
- Внутри .task {} у тебя сразу async-контекст – можно вызывать await напрямик.
- Логика асинхронки отделена от onAppear и проще читается.
Но это ещё не всё. Если нужна реакция на изменения, например ты стал что-то вводить, то ты можешь вызывать конструктор с id:
Теперь при изменении query предыдущая задача отменяется автоматически. Но и это ещё не все!
Ты можешь управлять приоритетом. По умолчанию приоритет – .userInitiated, но можно указать свой и для этого можно взять соответствующий конструктор:
Используй модификатор .task, чтобы SwiftUI сам заботился о запуске и отмене твоих async-задач!
Начиная с iOS 14 вместо Task {…} в onAppear начинаем юзать встроенный модификатор .task – он сам создаёт и отменяет задачу вместе с жизненным циклом View:
Text("Привет, мир!")
.task { // ✅ запускается при появлении и отменяется при уходе
await loadData()
}
Но зачем так делать?
- Не надо городить Task вручную и переживать об отмене.
- Внутри .task {} у тебя сразу async-контекст – можно вызывать await напрямик.
- Логика асинхронки отделена от onAppear и проще читается.
Но это ещё не всё. Если нужна реакция на изменения, например ты стал что-то вводить, то ты можешь вызывать конструктор с id:
.searchable(text: $query)
.task(id: query) { // каждый раз новый `query` – новая задача
results = await fetch(query)
}
Теперь при изменении query предыдущая задача отменяется автоматически. Но и это ещё не все!
Ты можешь управлять приоритетом. По умолчанию приоритет – .userInitiated, но можно указать свой и для этого можно взять соответствующий конструктор:
.task(priority: .background) {
await cleanupCache()
}
Используй модификатор .task, чтобы SwiftUI сам заботился о запуске и отмене твоих async-задач!
🔥14👍4😎3❤1
func saveData() {
Task {
updateData()
print("Дата сохранена!")
}
func updateData() {
Task.detached {
self.isSaved = true
}
}
}
Есть переменная isSaved типа Boolean. Будет ли фиолетовая ошибка — если запустить данный код? Мыслим в парадигме работы на SwiftUI и только / Без UIKit
P.S. сама сущность где отработает saveData() без аннотации @MainActor
🕊 - ДА / НЕТ
-----
Через 10 минут ответ в скрытом тексте, удачи 🙂
UPD:
- Если использовать макрос observable, там это не нужно и поэтому НЕТ, в контексте и ДА и НЕТ тоже верно, т.е смайл 🕊.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14👎2🕊2
Проверка на знание типов - но НААААМНОГО интереснее
Есть такая приватная функция _isPOD:
По-сути мы должны вспомнить, что есть что:
- Что есть примитивы
- Что есть ref type
- Что есть value type + ref type
И тветить будет ли выводить принт true или же false. Ну и самособой почему?🤔
Вот вам сам код:
И попробуй посмотреть на этот код и ответить:"Где true, а где false?". Ну а когда закончишь, то проверить можешь здесь.
Есть такая приватная функция _isPOD:
Приватная underscore функция проверяет, можно ли битово копировать метаданные типа без дополнительных операций retain / release или других скрытых семантик копирования /деструкции.
Если все поля типа сами являются POD: примитивные числовые типы, тривиальные структуры без custom инициализаторов или ссылочных полей, функция возвращает true; при наличии хотя бы одного неподы POD-поля — false.
По-сути мы должны вспомнить, что есть что:
- Что есть примитивы
- Что есть ref type
- Что есть value type + ref type
И тветить будет ли выводить принт true или же false. Ну и самособой почему?
Вот вам сам код:
struct A {
let one: StaticString
let two: Int
}
struct B {
let one: String
let two: Int
}
struct C {
let one: [String]
}
struct D {
let one: () -> Void
}
struct E {
let one: D
}
class F {
let one: Int = 2
}
struct G {
let one: Int
}
struct H {
let one: (Int, Float)
}
print(_isPOD(A.self))
print(_isPOD(B.self))
print(_isPOD(C.self))
print(_isPOD(D.self))
print(_isPOD(E.self))
print(_isPOD(F.self))
print(_isPOD(G.self))
print(_isPOD(H.self))
И попробуй посмотреть на этот код и ответить:"Где true, а где false?". Ну а когда закончишь, то проверить можешь здесь.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤4👍3
Подскажите пожалуйста, мы такое асуждаем или не асуждаем?
👍- асуждаем
👎- не асуждаем
https://ilovehackit.ru
👍- асуждаем
👎- не асуждаем
https://ilovehackit.ru
👍35👎19
Различие между наследование флага и автоматической отмены
Когда погружаешься в изучение structured concurrency, то можно упустить или запамятовать некоторые детали, а они бывают важными.
Так например есть разница между structured и unstructured tasks. И здесь даже можно спутаться, что есть structured, что есть unstructured... Но Apple отетила на этот вопрос твёрдо и чётко.
И здесь мы можешь заметить, что Task нарушает. А чтобы проверить, достаточно запустить и проверить:
И мы увидим, что это не одно и тоже как если бы мы поступили с представителем structured tasks - withThrowingTaskGroup:
Когда погружаешься в изучение structured concurrency, то можно упустить или запамятовать некоторые детали, а они бывают важными.
Так например есть разница между structured и unstructured tasks. И здесь даже можно спутаться, что есть structured, что есть unstructured... Но Apple отетила на этот вопрос твёрдо и чётко.
Структурированная конкурентность требует:
1. Scoped lifetime: дочерние задачи не могут пережить родительскую задачу.
2. Автоматическое ожидание: родитель должен дождаться всех дочерних задач перед завершением.
3. Fail-fast behavior: ошибки в дочерних задачах распространяются на родительскую.
4. Строгая иерархия parent-child: четкие отношения для распространения отмены и приоритета.
И здесь мы можешь заметить, что Task нарушает. А чтобы проверить, достаточно запустить и проверить:
func demonstrateUnstructuredTaskCancellation() async {
print("🔵 Демонстрация Task {} - unstructured")
let parentTask = Task {
print("👨 Parent task начала работу")
let childTask = Task {
print("👶 Child task начала работу")
// Проверяем отмену каждую секунду
for i in 1...5 {
if Task.isCancelled {
print("👶 Child обнаружила отмену на итерации \(i)")
return "Child завершилась по отмене"
}
print("👶 Child работает... итерация \(i)")
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
print("👶 Child завершила всю работу")
return "Child успешно завершилась"
}
// Ждем немного и отменяем parent
try? await Task.sleep(nanoseconds: 2_500_000_000)
print("👨 Parent отменяется!")
// Получаем результат child
let result = await childTask.value
print("👨 Parent получил результат: \(result)")
return "Parent завершен"
}
// Отменяем parent task через 2.5 секунды
parentTask.cancel()
let finalResult = await parentTask.value
print("🔵 Финальный результат: \(finalResult)")
print("🔵 Обратите внимание: child task продолжила работу после отмены parent!\n")
}
// Запуск примера
await demonstrateUnstructuredTaskCancellation()
И мы увидим, что это не одно и тоже как если бы мы поступили с представителем structured tasks - withThrowingTaskGroup:
👍3🔥2
func demonstrateStructuredTaskCancellation() async {
print("🟢 Демонстрация TaskGroup - structured")
do {
try await withThrowingTaskGroup(of: String.self) { group in
print("👨 TaskGroup начала работу")
// Запускаем три дочерние задачи
for i in 1...3 {
group.addTask {
print("👶 задача \(i) начала работу")
for j in 1...5 {
try Task.checkCancellation() // бросит CancellationError, если отменена
print("👶 задача \(i) итерация \(j)")
try await Task.sleep(nanoseconds: 1_000_000_000)
}
print("👶 задача \(i) завершилась")
return "задача \(i) успех"
}
}
// Ждём 2.5 секунды в этой же области и отменяем группу
try await Task.sleep(nanoseconds: 2_500_000_000)
print("👨 TaskGroup отменяет все задачи!")
group.cancelAll()
// Сбор завершённых результатов
var results: [String] = []
for try await result in group {
results.append(result)
print("👨 Получен результат: \(result)")
}
print("👨 TaskGroup завершена. Всего результатов: \(results.count)")
}
} catch {
print("🟢 TaskGroup завершилась с ошибкой: \(error)")
}
print("\n🟢 Все дочерние задачи в группе гарантированно либо отработали, либо были отменены.")
}
// Запуск примера
await demonstrateStructuredTaskCancellation()
Вот такой, небольшой, но интересный нюанс между наследованием флага отмены и автоматической отменой.
👍3🔥3
Swift Server Side Meetup #5
Да-да, движется по-немногоу. Прям как и сам язык swift в серверную разработку. Конечно свифту ещё далеко, но для тех кто на приколе серверной части для свита - рекомендую.
https://www.youtube.com/watch?v=0JrLkHgZa-k
Да-да, движется по-немногоу. Прям как и сам язык swift в серверную разработку. Конечно свифту ещё далеко, но для тех кто на приколе серверной части для свита - рекомендую.
https://www.youtube.com/watch?v=0JrLkHgZa-k
YouTube
Swift Server Side Meetup #5
**📅 Monday, June 23rd, 2025**
**🕖 7pm CEST (10am PDT / 1pm EDT)**
**🌐 Online – no registration needed**
We’re excited to invite you to the next Swift Server Side Meetup, where Swift takes a bold step into the physical world—from embedded microcontrollers…
**🕖 7pm CEST (10am PDT / 1pm EDT)**
**🌐 Online – no registration needed**
We’re excited to invite you to the next Swift Server Side Meetup, where Swift takes a bold step into the physical world—from embedded microcontrollers…
👍3🔥3❤1