#заметка #cow #устройство_работы
А ты знал, что Swift хранит счетчик сильных ссылок как "extra count" - дополнительное значение?🤔
Когда у объекта одна strong ссылка, в памяти хранится 0.
Когда две ссылки — хранится 1.
- Физическое значение = то, что реально хранится в битах.
- Логическое значение = реальное количество ссылок = физическое + 1
Именно поэтому
Это как номерки в гардеробе, которые начинаются с 0, а не с 1. Apple сэкономила на единичке, потому что одна ссылка — самый частый случай. А когда у нас миллиарды объектов, даже один бит на счету!
Представь диалог:
- Сколько у тебя ссылок?
- Ноль!
- То есть объект мёртв?
- Нет, это значит одна! Просто мы экономные
Մտածեք. Բաժանորդագրվել.
cc: https://github.com/swiftlang/swift/blob/eb29949fe7d2c90644410ef9cef76abe30658aad/stdlib/public/SwiftShims/swift/shims/RefCount.h#L609C3-L626C4
А ты знал, что Swift хранит счетчик сильных ссылок как "extra count" - дополнительное значение?
Когда у объекта одна strong ссылка, в памяти хранится 0.
Когда две ссылки — хранится 1.
- Физическое значение = то, что реально хранится в битах.
- Логическое значение = реальное количество ссылок = физическое + 1
// Практический пример с Copy-on-Write:
var array1 = [1, 2, 3]
// StrongExtraRefCount = 0 (в памяти)
// Реальных ссылок = 1 ✅ Можно изменять!
var array2 = array1
// StrongExtraRefCount = 1 (в памяти)
// Реальных ссылок = 2 ❌ Нужно копировать!
array2.append(4)
// Swift проверяет: getStrongExtraRefCount() == 0?
// Нет! Значит создаём копию массива
Именно поэтому
isKnownUniquelyReferenced проверяет getStrongExtraRefCount() == 0 - это означает, что есть только одна ссылка на объект, и его можно безопасно изменять без копирования.
bool isUniquelyReferenced() {
static_assert(Offsets::UnownedRefCountBitCount +
Offsets::IsDeinitingBitCount +
Offsets::StrongExtraRefCountBitCount +
Offsets::PureSwiftDeallocBitCount +
Offsets::UseSlowRCBitCount == sizeof(bits)*8,
"inspect isUniquelyReferenced after adding fields");
// Unowned: don't care (FIXME: should care and redo initForNotFreeing)
// IsDeiniting: false
// StrongExtra: 0
// UseSlowRC: false
// Compiler is clever enough to optimize this.
return
!getUseSlowRC() && !getIsDeiniting() && getStrongExtraRefCount() == 0;
}
Это как номерки в гардеробе, которые начинаются с 0, а не с 1. Apple сэкономила на единичке, потому что одна ссылка — самый частый случай. А когда у нас миллиарды объектов, даже один бит на счету!
Представь диалог:
- Сколько у тебя ссылок?
- Ноль!
- То есть объект мёртв?
- Нет, это значит одна! Просто мы экономные
Մտածեք. Բաժանորդագրվել.
cc: https://github.com/swiftlang/swift/blob/eb29949fe7d2c90644410ef9cef76abe30658aad/stdlib/public/SwiftShims/swift/shims/RefCount.h#L609C3-L626C4
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
swift/stdlib/public/SwiftShims/swift/shims/RefCount.h at eb29949fe7d2c90644410ef9cef76abe30658aad · swiftlang/swift
The Swift Programming Language. Contribute to swiftlang/swift development by creating an account on GitHub.
🔥5❤2👍1🌚1
#wwdc25
Improve memory usage and performance with Swift
Сессия с WWDC25, где расскажут про InlineArray и его разницу между Array из Swift, причным нам. Спойлер - копируется сразу, CoW не поддерживает. Ну и как работа с InlineArray сделает работу ещё-более оптимизированной на ресурсы (график увидишь на сессии).
Так же понравилось, в самом начале, что при помощи Instruments: Time Profiler и Allocations, можно продебажить на bottle neck - "узкое горлыжко" в приложении. Посмотреть колличество аллокаций, деаллокаций, фильтранутьсветлого нужное и прыгнуть в проблемное место.
Ну и под конец будет про новую обёртку - Span. Всё это уже можно посмотреть / потрогать в Xcode 26. Жаль в wwdc notes ещё нет краткого пересказа, но возможно, он скоро будет? - Если-что вот ссылка на него 🙂
https://developer.apple.com/videos/play/wwdc2025/312
Improve memory usage and performance with Swift
Сессия с WWDC25, где расскажут про InlineArray и его разницу между Array из Swift, причным нам. Спойлер - копируется сразу, CoW не поддерживает. Ну и как работа с InlineArray сделает работу ещё-более оптимизированной на ресурсы (график увидишь на сессии).
Так же понравилось, в самом начале, что при помощи Instruments: Time Profiler и Allocations, можно продебажить на bottle neck - "узкое горлыжко" в приложении. Посмотреть колличество аллокаций, деаллокаций, фильтрануть
Ну и под конец будет про новую обёртку - Span. Всё это уже можно посмотреть / потрогать в Xcode 26. Жаль в wwdc notes ещё нет краткого пересказа, но возможно, он скоро будет? - Если-что вот ссылка на него 🙂
https://developer.apple.com/videos/play/wwdc2025/312
Apple Developer Documentation
Span | Apple Developer Documentation
represents a contiguous region of memory which contains initialized instances of .
👍5❤1🔥1
#middle #задачка
Что из перечисленного ниже нельзя переопределить в подклассе? Опрос будет ниже🤖
Что из перечисленного ниже нельзя переопределить в подклассе? Опрос будет ниже
class Vehicle {
static let wheels = 4
class var description: String {
return "Vehicle with \(wheels) wheels"
}
}
class Motorcycle: Vehicle {
override static let wheels = 2
override class var description: String {
return "Motorcycle with 2 wheels"
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
#заметка #soft_skills
История одной задачи + софт скиллы в деле с QA и Backend
Доброго дня. Решил начать писать небольшие заметки про софт скиллы. Кто знает, мб в отдельное видео, со структурой и гайдом выйдет. Но пока этого нет - буду чуть по чуть сюда писать интересные вещи.
Давечне мне надо было починить баг - отсутствие переводов для некоторых языков. Этот баг выглядит просто:"Наверное затерялась локализация для необходимы языков, сейчас пойду поправлю. Делов на 5 минут."
Так как проект немаленький, то найти нужные строки и нужный участок кода - дело не на 5 минут, а минут на 15. Хотя хотелось - бы на 5, но что поделать... Нашел нужное место, оказалось, что дело не в строках или ключах, а в том, что бекенд присылает текст всегда на англйиском.
Иду смотреть в задачу, и нигде не вижу об этом ни слова. И тут я хотел-бы добавить, что не во всех компаниях или проектах тестировщики должны собирать логи. Или собирать логи прям везде и до 3-его колена. Нет, всё как всегда просто - как договорились, так и будете работать.
Так вот, оказывается тестер не написал этот факт, что текст приходит с бекенда, и что iOS тут особо ничего и не сделает, а задча должна БЫЛА БЫ содержать лейбл [backend], а не [iOS], но что поделать...
Иду до тестера и кумекаю, что так и так, что задача так-то не про iOS, а про backend, но тестеру не нужно волноваться, я сейчас схожу и уточню.
Иду в нужное место, тегаю PM, Backend и пишу, что текст, который багает, он приходит бекенда, и что лучше править на бекенде в одном месте, чем на iOS и Android отдельно - в двух местах. И аргументирую это тем, что если править на 2-ух платформах сразу, то это придётся:
А зачем править в двух местах одинаковой логикой, плюс закидывать текста, которые сейчас присылает, хоть и частично, бекенд - если на бекенде можно доработать, в одном месте.
Cверху накинул, что можно взять текущую ручку, добавить к ней параметр языка, чтобы backend'у было проще, при реализации фикса, принимать параметр языка и с ним уже идти за переводом и отдавать нужный текст, а не стучаться в микросервис локализации, смотреть текущую локаль и только после этого отдавать нужный текст.
Какой вывод можно сделать из этой истории?
Не стоит идти к тестировщику и как-то язвить или сетовать на то, что он оказался где-то неправ. Потому-что напомню:
- Как договорились в команде так и будет.
- Опыт коллеги, кума, зятя, соседа не всегда релевантный к тебе, т.к ты не всегда знаешь всех под-капотных вещей.
Если - бы я отправил тестера вместо себя изучать, ибо проблема backend'a, то мог - бы получиться сломанный телефон из 3-ёх человек + к этому долго бы обсуждали. А лично я не люблю тягомотину эту, когда понимаешь, что с буксом + хрустом можно за 5 минут обговорить и сделать, чем 30 минут выяснять кто прав, а кто виноват и придти к такому-же результату.
Возможность для выноса на ретроспективу, чтобы тестировщики проверяли чуть глубже, если они этого не делают. А если должен делать, но конкретно тут [по какой-то причине забыл сделать], то в мягкой форме донести:"Что мне бы помогло, если-бы в результате заведения бага были логи".
Все мы люди, разные бывают обстоятельства и зачем токсичить или язвить, если можно этого не делать? - Если - вдруг ты считаешь, что токсичишь, то всегда можно:
- После написания текста не отправлять его, взять пауза на 5 минут. Спустя паузу перечитать.
- Закинуть ИИ на оценку токсичности, и в случае её обнаружения попросить поправить. А что нет то, мы ж не пишем рассказ, а доносим мысль.
Ну и последнее, чтобы backend'у было легче, я сразу же заострил внимание, что можно сделать легче и без проблем - прокинуть дополнительный параметр и по нему получать перевод. Потому-что для backend'a пойти в другой микросервис, узнать там локаль, с этими знаниями придти обратно - это лишние сложности.
А мы бы их создали, если бы могли упереться, не согласиться, дескать вот пусть backend разруливает сам ибо мы просто получаем и показываем... Разные ветви пути могли-бы быть...
История одной задачи + софт скиллы в деле с QA и Backend
Доброго дня. Решил начать писать небольшие заметки про софт скиллы. Кто знает, мб в отдельное видео, со структурой и гайдом выйдет. Но пока этого нет - буду чуть по чуть сюда писать интересные вещи.
Давечне мне надо было починить баг - отсутствие переводов для некоторых языков. Этот баг выглядит просто:"Наверное затерялась локализация для необходимы языков, сейчас пойду поправлю. Делов на 5 минут."
Так как проект немаленький, то найти нужные строки и нужный участок кода - дело не на 5 минут, а минут на 15. Хотя хотелось - бы на 5, но что поделать... Нашел нужное место, оказалось, что дело не в строках или ключах, а в том, что бекенд присылает текст всегда на англйиском.
Иду смотреть в задачу, и нигде не вижу об этом ни слова. И тут я хотел-бы добавить, что не во всех компаниях или проектах тестировщики должны собирать логи. Или собирать логи прям везде и до 3-его колена. Нет, всё как всегда просто - как договорились, так и будете работать.
Так вот, оказывается тестер не написал этот факт, что текст приходит с бекенда, и что iOS тут особо ничего и не сделает, а задча должна БЫЛА БЫ содержать лейбл [backend], а не [iOS], но что поделать...
Иду до тестера и кумекаю, что так и так, что задача так-то не про iOS, а про backend, но тестеру не нужно волноваться, я сейчас схожу и уточню.
Иду в нужное место, тегаю PM, Backend и пишу, что текст, который багает, он приходит бекенда, и что лучше править на бекенде в одном месте, чем на iOS и Android отдельно - в двух местах. И аргументирую это тем, что если править на 2-ух платформах сразу, то это придётся:
- Делать небольшую логику в 2-ух местах
- Заводить локализацию
- Маппить нужное место с нужной локализацией
А зачем править в двух местах одинаковой логикой, плюс закидывать текста, которые сейчас присылает, хоть и частично, бекенд - если на бекенде можно доработать, в одном месте.
Cверху накинул, что можно взять текущую ручку, добавить к ней параметр языка, чтобы backend'у было проще, при реализации фикса, принимать параметр языка и с ним уже идти за переводом и отдавать нужный текст, а не стучаться в микросервис локализации, смотреть текущую локаль и только после этого отдавать нужный текст.
Какой вывод можно сделать из этой истории?
Не стоит идти к тестировщику и как-то язвить или сетовать на то, что он оказался где-то неправ. Потому-что напомню:
- Как договорились в команде так и будет.
- Опыт коллеги, кума, зятя, соседа не всегда релевантный к тебе, т.к ты не всегда знаешь всех под-капотных вещей.
Если - бы я отправил тестера вместо себя изучать, ибо проблема backend'a, то мог - бы получиться сломанный телефон из 3-ёх человек + к этому долго бы обсуждали. А лично я не люблю тягомотину эту, когда понимаешь, что с буксом + хрустом можно за 5 минут обговорить и сделать, чем 30 минут выяснять кто прав, а кто виноват и придти к такому-же результату.
Возможность для выноса на ретроспективу, чтобы тестировщики проверяли чуть глубже, если они этого не делают. А если должен делать, но конкретно тут [по какой-то причине забыл сделать], то в мягкой форме донести:"Что мне бы помогло, если-бы в результате заведения бага были логи".
Все мы люди, разные бывают обстоятельства и зачем токсичить или язвить, если можно этого не делать? - Если - вдруг ты считаешь, что токсичишь, то всегда можно:
- После написания текста не отправлять его, взять пауза на 5 минут. Спустя паузу перечитать.
- Закинуть ИИ на оценку токсичности, и в случае её обнаружения попросить поправить. А что нет то, мы ж не пишем рассказ, а доносим мысль.
Ну и последнее, чтобы backend'у было легче, я сразу же заострил внимание, что можно сделать легче и без проблем - прокинуть дополнительный параметр и по нему получать перевод. Потому-что для backend'a пойти в другой микросервис, узнать там локаль, с этими знаниями придти обратно - это лишние сложности.
А мы бы их создали, если бы могли упереться, не согласиться, дескать вот пусть backend разруливает сам ибо мы просто получаем и показываем... Разные ветви пути могли-бы быть...
🔥4👍2❤1
Какой вывод можно сделать?
Если понравилось, жду голубя, буду софтовыми вещами по-чаще делиться, если нужна reels version, то голубя ставь.
1. Понимание, хоть и небольшое, backend части может улучшить всем жизнь.
2. Задачки на фиксы багов с репортами - это гуд, так как не нужно будет тратить время на поиск причины бага. Если тестер уже на этом пути, иногда лишиние 5-10 минут сэкономят твои 30-60 минут.
3. Если хочется ткнуть носом в промах человека, то лучше вспомнить, что не все и всегда и во все периоды времени работают на полную мощнь.
4. Видишь место для улучшения работы? Запиши, ибо забудешь, а на ретро можно обсудить
5. Если человек человеку волк, то почему зомби зомби зомби?
Если понравилось, жду голубя, буду софтовыми вещами по-чаще делиться, если нужна reels version, то голубя ставь.
🕊16🔥2👍1
Полный экскурс по разработке + день iOS Разработчика
Почти 1 год прошел с публикации этого видео, где я полностью и по полочкам раскидал важное и необходиоме для тех, кто хочет понимать:"А что же там происходит, внутри этой разработки?". Вот небольшой список тем:
- Кто состоит в команде и чем занимается
- Какие задачи и откуда они берутся
- Feature / Core team, а что это вообще?
- Мобильный девопс и что он делает? Кстати подробный воркшоп и про него есть, он здесь
- Про каждый процесс подробно + дополнительные активности, опционально.
И это лишь малая часть того, что есть внутри видео. Из этого видео можно понять, и очень даже неплохо, про внутренню кухню внутри разработки ПО.
Как - всегда, все подробные таймкоды ждут внутри. Презентация и пояснение = результат 🙂
Почти 1 год прошел с публикации этого видео, где я полностью и по полочкам раскидал важное и необходиоме для тех, кто хочет понимать:"А что же там происходит, внутри этой разработки?". Вот небольшой список тем:
- Кто состоит в команде и чем занимается
- Какие задачи и откуда они берутся
- Feature / Core team, а что это вообще?
- Мобильный девопс и что он делает? Кстати подробный воркшоп и про него есть, он здесь
- Про каждый процесс подробно + дополнительные активности, опционально.
И это лишь малая часть того, что есть внутри видео. Из этого видео можно понять, и очень даже неплохо, про внутренню кухню внутри разработки ПО.
Как - всегда, все подробные таймкоды ждут внутри. Презентация и пояснение = результат 🙂
YouTube
Полный разбор работы iOS-разработчика: команда, спринты и мой рабочий день
Детальный разбор работы iOS-разработчика в продуктовой команде - от первого дня до профессиональных процессов.
Разбираем команду:
- Project Manager - планирование и координация
- Designer - от макетов до готового UI
- Business Analyst - требования и логика…
Разбираем команду:
- Project Manager - планирование и координация
- Designer - от макетов до готового UI
- Business Analyst - требования и логика…
🔥12❤6👍6🫡1
#middle #задачка
Старая добрая задача на print + работа с замыканием. Самые разные вариации с ДАНО: value / ref type и тоже самое с замыканием - implicit capture vs explicit capture.
Посмотри на код ниже, хорошо подумай, и выбери нужный вариант ответа, будет следующим постом.
Старая добрая задача на print + работа с замыканием. Самые разные вариации с ДАНО: value / ref type и тоже самое с замыканием - implicit capture vs explicit capture.
Посмотри на код ниже, хорошо подумай, и выбери нужный вариант ответа, будет следующим постом.
final class Person {
var name: String
init(name: String) {
self.name = name
}
}
var person = Person(name: "Alice")
let closure1 = {
print(person.name)
}
let closure2 = { [person] in
print(person.name)
}
person.name = "Bob"
closure1() // Что выведет тут? [1]
closure2() // Что выведет тут? [2]
person = Person(name: "Charlie")
closure1() // Что выведет тут? [3]
closure2() // Что выведет тут? [4]
👍1
В сети интернет ходит интересная стать про перформанс SwiftUI и способы на него взаимодействовать, благоприятно. Хочу сразу подсветить, что эта информация актуальна для 13-16 версии, начиная с 17 доступен макрос Observable, который оптимизирован в плане перформанса.
Не поделиться не могу, поэтому вот: https://medium.com/airbnb-engineering/understanding-and-improving-swiftui-performance-37b77ac61896
Но хочу добавить, что это давным-давно есть сами знаете где и намного подробнее 🙂
Но статью прочитать тоже стоит, зря старались коллеги из Airbnb?👍
Не поделиться не могу, поэтому вот: https://medium.com/airbnb-engineering/understanding-and-improving-swiftui-performance-37b77ac61896
Но хочу добавить, что это давным-давно есть сами знаете где и намного подробнее 🙂
Но статью прочитать тоже стоит, зря старались коллеги из Airbnb?
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
Understanding and improving SwiftUI performance
New techniques we’re using at Airbnb to improve and maintain performance of SwiftUI features at scale.
🔥6👍3😁1
#swiftui #собеседование #jun
Доброй ночи! Такая задача на подумать. Сколько раз выведется принт:"evaluate body", если сделать два действия:
1. Запустить код, чтобы отобразить VIew
2. Нажать на кнопку
Варианты ответа будут ниже!
Доброй ночи! Такая задача на подумать. Сколько раз выведется принт:"evaluate body", если сделать два действия:
1. Запустить код, чтобы отобразить VIew
2. Нажать на кнопку
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
@State var value = 0
var body: some View {
let _ = print("evaluate body")
Button("Изменить") {
value += 1
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
Варианты ответа будут ниже!
🤓5🔥3🤝3
#swiftui #собеседование #middle
Мы поменяли @State var value = 0 на @StateObject var viewModel и дёргаем increment. Так же сделаю 2 действия: запущу это код, чтобы отобразить view и нажму на кнопку. За два этих действия сколько раз вызовется принт “re-evaluate body”? И почему?
Опрос будет ниже, перед выбором нужного ответа постарайся обосновать свой ответ, почему именно ЭТА цифра.
Мы поменяли @State var value = 0 на @StateObject var viewModel и дёргаем increment. Так же сделаю 2 действия: запущу это код, чтобы отобразить view и нажму на кнопку. За два этих действия сколько раз вызовется принт “re-evaluate body”? И почему?
import SwiftUI
import PlaygroundSupport
final class ViewModel: ObservableObject {
@Published var age: Int = 0
func increment() {
age += 1
}
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
let _ = print("evaluate body")
Button("Изменить") {
viewModel.increment()
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
Опрос будет ниже, перед выбором нужного ответа постарайся обосновать свой ответ, почему именно ЭТА цифра.
👍1🔥1
🔥6
#swiftui #собеседование #middle
Окей с двумя премерами выше мы разобрались. У нас есть правильный ответ и обоснование его. Если-вдруг есть сомнения в корректности, всегда можно проверить в Playground.
И чтобы продолжить ветку этого вопроса дальше, давай теперь ответим на следующий вопрос. Ответы выбирай тот, который считаешь НАИБОЛЕЕ корректным.
"В чём разница между re-evaluate и re-draw? Что происходит в предыдущем примере: re-evaluate и / или re-draw?"
Окей с двумя премерами выше мы разобрались. У нас есть правильный ответ и обоснование его. Если-вдруг есть сомнения в корректности, всегда можно проверить в Playground.
И чтобы продолжить ветку этого вопроса дальше, давай теперь ответим на следующий вопрос. Ответы выбирай тот, который считаешь НАИБОЛЕЕ корректным.
"В чём разница между re-evaluate и re-draw? Что происходит в предыдущем примере: re-evaluate и / или re-draw?"
#swiftui #собеседование #middle+
Есть такой код и при нажатии на кнопку “Увеличить возраст на 1 ед.” счётчик counter не увеличивается и не показывает числа, он всегда показывает 0.
Задача - понять почему, пофиксить и объяснить в чём была проблема. Код при этом, концептуально, должен остаться таким же, какой он изначально, не считая исправления.
Есть такой код и при нажатии на кнопку “Увеличить возраст на 1 ед.” счётчик counter не увеличивается и не показывает числа, он всегда показывает 0.
Задача - понять почему, пофиксить и объяснить в чём была проблема. Код при этом, концептуально, должен остаться таким же, какой он изначально, не считая исправления.
import SwiftUI
import PlaygroundSupport
final class ViewModel: ObservableObject {
@Published var age: Int = 0
func increment() {
age += 1
}
}
struct ChildView: View {
@ObservedObject var viewModel = ViewModel()
@Binding var value: Int
var body: some View {
Button("Увеличить возраст на 1 ед.") {
viewModel.increment()
}
.onChange(of: viewModel.age) { _, newValue in
value = newValue
}
}
}
struct ContentView: View {
@State private var counter: Int = 0
var body: some View {
VStack(alignment: .center, spacing: 0) {
Text("Каунтер равен:\(counter)")
.font(.title)
.foregroundStyle(.teal)
ChildView(value: $counter)
}
.frame(width: 300, height: 500)
}
}
PlaygroundPage.current.setLiveView(ContentView())
#structured_concurrency #собеседование #middle
Нужно сказать на каком thread будет выполняться операция в контексте background или main thread, учитывая что Playground по-умолчанию равен background thread.
Нужно сказать на каком thread будет выполняться операция в контексте background или main thread, учитывая что Playground по-умолчанию равен background thread.
Task {
showCurrentThread() // 1 ?
await asyncOperation // 2 ?
showCurrentThread // 3 ?
}
Task { @MainActor in
showCurrentThread() // 4 ?
await asyncOperation // 5 ?
showCurrentThread // 6 ?
}
func asyncOperation(line: Int = #line) async {
showCurrentThread(line: line)
try? await Task.sleep(for: .seconds(1))
}
func showCurrentThread(line: Int = #line) {
print("Current line is: \(line) and thread is: \(Thread.current)")
}