#Playground в Xcode 26: запускаем код без лишних файлов.С выходом Xcode 26 появился удобный инструмент для быстрого тестирования кода прямо в проекте — макрос
#Playground. Теперь не нужно создавать отдельные .playground файлы, чтобы проверить идею.import Playgrounds
#Playground {
let person = Person(name: "Артем")
print(person.name.uppercased())
}
После чего смотрим результат в Canvas (как с SwiftUI превью, пример на изображении).
🔹 Экономия времени — не нужно переключаться между файлами.
🔹 Тестирование на реальных данных — используете структуры из проекта.
🔹 Несколько превью в одном файле — можно подписать каждое:
#Playground("Проверка имени") {
print(Person(name: "Анна").name.count)
}🔸 Требует Xcode 26+ и iOS 18/macOS 15.
🔸 Пока нет поддержки интерактивного редактирования (как в обычных Playgrounds).
#Playground — это лайт-версия Playgrounds прямо в рабочих файлах. Не заменяет полноценные .playground файлы для сложных экспериментов, но идеален для повседневных задач.Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥12❤6👀1
На WWDC25 компания Apple представила новые компоненты WebView и WebPage, которые значительно упрощают интеграцию веб-контента в SwiftUI приложения, которые доступны с iOS 18.4.
Отслеживание состояния:
@State private var isLoading: Bool = false
@State private var progress: Double = 0.0
WebPage(url: URL(string: "https://t.me/hardworkerIT"))
.onLoadingChanged { loading in
isLoading = loading
}
.onProgressChanged { progress in
self.progress = progress
}
Обработка событий навигации (currentNavigationEvent), таких как ошибки, перенаправления, завершение загрузки.
Теперь есть возможность сохранения веб-контента в следующих форматах:
🔹 Снимки экрана (PNG/JPEG).
🔹 PDF.
🔹 Веб-архивы (полное сохранение страницы).
WebPage(url: someURL)
.saveSnapshot(as: .pdf) { result in
switch result {
case .success(let data):
// Сохраняем PDF
case .failure(let error):
print("Ошибка: \(error)")
}
}
Есть возможность отображения сохраненных страниц:
WebArchiveView(data: archivedData)
🔹 Скролл к определённому элементу на странице.
🔹 Расширенное взаимодействие с JavaScript.
🔹 Кастомные обработчики для ссылок и форм.
🔸 Проще, чем WKWebView — не нужно писать обёртки для SwiftUI.
🔸 Нативные состояния загрузки — больше никаких кастомных индикаторов.
🔸 Готовые решения для экспорта и архивирования.
🔹 Требуется iOS 18.4+ / macOS 15.4+.
🔹 Для сложных сценариев (например, кастомные схемы URL) всё ещё может потребоваться WKWebView.
Больше информации доступно в официальной документации.
Новые API делают работу с веб-контентом в SwiftUI такой же простой, как и с любыми другими вью. Теперь встраивать браузеры, документацию или веб-интерфейсы стало ещё удобнее!
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥23❤11👍6👀2
На WWDC25 компания Apple представила Xcode 26 с революционным ИИ ассистентом, который переосмысливает процесс создания приложений. Вот что ждет разработчиков.
ИИ помощник: код как диалог.
🔹 Анализирует стиль кода и предлагает персонализированные варианты.
🔹 Генерирует шаблонный код (делегаты, сетевые запросы).
🔹 Находит синтаксические и логические баги до запуска.
🔹 Подсказывает оптимизации для Swift / Objective-C.
// Вы начинаете печатать:
@State private var isLoading = false
// ИИ сразу предлагает:
.onChange(of: isLoading) { newValue in
print("Loading state changed: \(newValue)")
}
Тесная интеграция с экосистемой Apple.
🔹 Swift Playgrounds: ИИ помогает экспериментировать с кодом в реальном времени.
🔹 TestFlight: автоматически анализирует краши и предлагает фиксы.
🔹 Core ML: упрощает внедрение ML-моделей (подсказывает код для обработки данных).
Мультиязыковая поддержка.
ИИ работает с:
🔹 Swift (приоритет).
🔹 Objective-C.
🔹 C++.
🔹 SwiftUI / UIKit.
Отладка нового уровня.
🔹 Определяет корневую причину падений.
🔹 Предлагает готовые решения.
🔹 Показывает графики потребления CPU / памяти.
🔹 Выявляет утечки без Instruments.
🔸 Скорость: на 30-50% меньше рутинных задач.
🔸 Качество: меньше багов в продакшене.
🔸 Доступность: новым разработчикам проще входить в экосистему.
🔸 Mac на Apple Silicon (M1+).
🔸 Xcode 26 (минимум).
Xcode 26 — это не просто обновление, а смена парадигмы. Теперь ИИ берет на себя шаблонные задачи, оставляя вам творческую часть — архитектуру и инновации.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥24👍11❤7👏1
В SwiftUI появился долгожданный инструмент для точного контроля отступов в секциях List — модификатор listSectionMargins(). Теперь можно гибко настраивать отступы для отдельных секций, не прибегая к костылям.
Модификатор принимает:
🔸 edges — стороны для отступов (по умолчанию .all).
🔸 length — величина отступа в точках.
List {
Section("Новости") {
Text("Свежие обновления")
}
.listSectionMargins(.horizontal, 20) // Отступы по бокам
Section("Профиль") {
Text("Настройки")
}
.listSectionMargins(.top, 10) // Отступ сверху
}
🔹 Переопределяет стандартные отступы: заменяет дефолтные отступы, заданные стилем списка.
🔹 Работает с заголовками/подвалами: отступы применяются вокруг header и footer секции.
🔹 Гибкость: можно задавать для конкретных сторон (.horizontal, .vertical, .top и т.д.) или для всех сторон сразу (.all).
🔹 Не влияет на отступы между ячейками (для этого по-прежнему используем listRowSpacing).
🔸 Неочевидные комбинации padding() + listRowInsets().
🔸 Кастомные разделители.
🔸 Костыли с GeometryReader.
Теперь всё решается одним модификатором!
listSectionMargins() — это отличное дополнение для тонкой настройки списков!
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥25👍9❤6👀2
В Swift и классы, и actor используются для создания ссылочных типов, но с разными целями. Главное отличие — в потокобезопасности. Actor появились в Swift 5.5 как часть Concurrency.
🔹 Не потокобезопасны: доступ к свойствам и методам из разных потоков может привести к гонкам данных.
🔹 Поддерживают наследование: можно создавать подклассы.
🔹 Используются для общего состояния: подходят для объектов, которые не требуют синхронизации.
class Counter {
var value = 0
func increment() {
value += 1 // Опасность при вызове из разных потоков
}
}
🔹 Потокобезопасны: Swift автоматически сериализует доступ к свойствам и методам (очередь задач).
🔹 Нет наследования: нельзя наследовать от actor.
🔹 Для изолированного состояния: идеальны для данных, которые изменяются из разных потоков.
actor SafeCounter {
private var value = 0
func increment() {
value += 1 // Безопасно (автоматическая синхронизация)
}
func currentValue() -> Int {
return value
}
}
let counter = SafeCounter()
Task {
await counter.increment()
let value = await counter.currentValue()
print(value) // 1
}
🔸 Для вызова методов actor нужен await.
🔸 Свойства actor по умолчанию private.
🔹 Классы — для простых объектов без многопоточности.
🔹 Actor — для данных, изменяемых из разных потоков (счетчики, кеши, состояния).
Если нужно потокобезопасное решение — выбирайте actor. Если важна гибкость и наследование — class.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥10❤7🫡1
И почему стаж ≠ опыт.
Грейды в IT — не про годы опыта, а про образ мышления. Вот ключевые различия между джуном и сеньором, которые заметны в реальной работе.
Джун:
🔹 Фокусируется на своей задаче.
🔹 Пишет код по ТЗ, не всегда понимая, как он влияет на систему.
Сеньор:
🔹 Видит связи между компонентами.
🔹 Спрашивает: как это повлияет на поддержку, бизнес или пользователей?
🔹 Выбирает простые, но надежные решения, даже если они менее модные.
Джун:
🔹 Исправляет баги, если их явно указали.
🔹 Может переложить проблему: «Это не мой модуль».
Сеньор:
🔹 Не оставляет баги в проде, даже если это не его зона ответственности.
🔹 Понимает: код — это не абстракция, а функционал для живых людей.
Джун:
🔹 Учится у других, редко делится знаниями.
🔹 В код ревью пишет минорные замечания, без изучения глубокой логики.
Сеньор:
🔹 Находит слабые места в команде и помогает их закрыть.
🔹 Дает тактичные замечания при code review, объясняет почему следует внести исправления с аргументами, а не только указывает на проблемный код.
🔹 Говорит: давай разберем твой подход вместе, вместо ты неправ.
Джун:
🔹 Хочет использовать новейший стек, потому что так круто.
🔹 Пишет на SwiftUI, когда нужен UIKit (и наоборот).
Сеньор:
🔹 Выбирает инструменты под конкретную задачу и бюджет.
🔹 Может выполнить рекомендацию по использованию стабильного стека, если видит в этом больше плюсов, а не использует все самое модное и нестабильное.
Джун:
🔹 Стремится добавить фичу любой ценой.
🔹 Может переписать рабочий код для красоты.
Сеньор:
🔹 Избегает изучение лишней информации, которая никогда не пригодится.
🔹 Говорит: этот легаси работает — не трогаем или автоматизируем в следующем квартале.
Джун:
🔹 Ждет четких ТЗ.
🔹 Паникует, если требования меняются.
Сеньор:
🔹 Самостоятельно уточняет детали у бизнеса.
🔹 Предлагает MVP решения при нехватке данных.
Сеньор — это не про количество строк кода, а про:
Как говорил один мудрый тимлид: джун думает, как написать. мидл — что написать. сеньор — стоит ли писать.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28❤12🫡7👀1
Во второй половине 2023 года, после множества доработок чужих приложений на фрилансе, связанных с улучшением здоровья и качества жизни, у меня появилась идея создать собственный счетчик отказа от вредных привычек.
💚 Счетчик дней: вредные привычки.
Конечно, счетчик дней без вредных привычек — не новинка. Но я добавил уникальный функционал, которого не было у конкурентов:
Моя цель – помочь людям бросить вредные привычки и заменить их полезными, а соревновательный элемент делает процесс более мотивирующим и увлекательным.
В скором времени планируется новое обновление, которое привнесет еще больше интересных возможностей в приложение.
🔹 Приложение «Счетчик дней: вредные привычки» для iOS, watchOS и macOS разработано на SwiftUI.
🔹 Версия для Android разработана на Flutter.
🔹 Серверную часть для приложения разрабатывал самостоятельно на PHP.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤18🔥10👏1
На WWDC25 Apple представила новые API для работы с AttributedString в SwiftUI, позволяющие создавать мощные текстовые редакторы с гибким форматированием.
Готовые стили:
🔹 Поддержка жирного текста, курсива, подчеркивания, зачеркивания.
🔹 Изменение размера шрифта и цвета текста.
Кастомные атрибуты:
🔹 Можно добавлять собственные правила форматирования.
Безопасное редактирование:
🔹 AttributedTextValueConstraint ограничивает допустимые атрибуты.
🔹 TextEditor автоматически применяет заданные правила.
Динамическое обновление:
🔹 SwiftUI корректно обрабатывает изменения текста и выделения.
🔸 Редакторы статей/рецептов (как в демо WWDC).
🔸 Приложения для заметок с расширенным форматированием.
🔸 Чат-боты с поддержкой стилизованного текста.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🔥9🙏7👀1
Ещё недавно компании боролись за разработчиков, а сегодня на одну вакансию — сотни резюме.
Сегодня вакансий меньше, конкуренция выше, а компании стали жестче отбирать кандидатов. Но хорошие офферы никуда не делись — просто теперь нужно действовать умнее.
🔹 Важно иметь минимум 3 года коммерческого опыта (фриланс и пет-проекты считаются, но котируются меньше).
🔹 Цифры и факты вместо общих фраз. Не «оптимизировал приложение», а «снизил потребление памяти на 25%».
🔹 Если есть пробелы в опыте работы, лучше их закрыть фрилансом или пет проектами.
🔹 Проверьте резюме через ChatGPT или hh-аналитику — даже мелкие ошибки могут отсеять вас.
🔹 Приложите портфолио к резюме. Примеры ваших работ позволят оценить ваш опыт.
🔹 Будьте готовы к лайвкодингу. Без умения решать задачи на глазах у интервьюера шансы равны нулю.
🔹 Тренируйте алгоритмы (LeetCode должен решаться на автомате).
🔹 Перед собеседованием обязательно ищите слитые разборы вопросов по компании (телеграм чаты, форумы, статьи в интернете).
Жирные офферы получают специалисты, умеющие продать себя. Разработчиков много, поэтому берут тех, кого видно. Вот несколько советов, как стать заметнее:
🔹 Ведите технический блог (даже 1 статья в месяц — уже очень хорошо).
🔹 Участвуйте в опенсорс-проектах (это новый must-have для middle+).
🔹 Делайте разборы кейсов в LinkedIn (работодатели это проверяют).
🔹 Выступайте публично, на ИТ мероприятиях или онлайн конференциях.
Медийность = доверие. Если о вас знают, шанс получить оффер гораздо выше.
🔹 Рынок работодателя: вакансий меньше, чем кандидатов.
🔹 Жалобы не помогут: либо адаптируешься, либо останешься без оффера.
🔹 Компании ищут готовых специалистов: доучиваться за их счет не больше не выйдет.
🔹 Удалёнка для джунов почти умерла: готовьтесь к гибридному формату.
🔹 Зарплаты стабилизировались: зп 400к для мидлов осталась в 2023 году.
🔹 Слабые отсеиваются: но те, кто вкатывает, продолжают брать топовые предложения.
Да, рынок уже не тот, но офферы всё ещё есть — их просто получают те, кто готовится лучше других и вкладывается в свою экспертность.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤30🙏13👍8👀1
NavigationStack — это новый (с iOS 16+) и более мощный способ организации навигации в SwiftUI. В отличие от NavigationView, он дает полный контроль над стеком экранов и поддерживает сложные сценарии.
🔹 Программное управление стеком экранов (пуш, поп, переход к корню).
🔹 Глубокая навигация по ссылкам (например, app://products/123).
🔹 Кастомные переходы между экранами.
🔹 Поддержка NavigationPath для хетерогенных данных в стеке.
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
NavigationLink("Экран 1", value: 1)
NavigationLink("Экран 2", value: "Текст")
}
.navigationDestination(for: Int.self) { value in
Text("Число: \(value)")
}
.navigationDestination(for: String.self) { value in
Text(value)
}
}
}
}
Тип-обертка для управления стеком. Может содержать разные типы данных:
path.append(1)
path.append("ABC")
path.removeLast()
Определяет, какой экран показывать для каждого типа данных:
.navigationDestination(for: Product.self) { product in
ProductView(product: product)
}
Button("Перейти к экрану 3") {
path.append(3)
}
Button("Назад") {
path.removeLast()
}
Button("В корень") {
path.removeLast(path.count)
}
Можно привязать навигацию к URL:
NavigationStack(path: $path) {
}
.onOpenURL { url in
if url.path == "/products/123" {
path.append(Product(id: 123))
}
}
🔸 Для iOS 15 и ниже используйте NavigationView.
🔸 Для модальных окон — sheet или fullScreenCover.
🔸 Не смешивайте NavigationStack и NavigationView.
NavigationStack — это эволюция навигации в SwiftUI. Он идеален для приложений со сложной навигацией, программного управления историей экранов и лубоких ссылок.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28🔥12🤝6❤1🫡1 1
This media is not supported in your browser
VIEW IN TELEGRAM
Установите бета-версию macOS Tahoe и Xcode 26, если хотите попробовать эту функцию.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥29❤12👍8🤯1 1
Universal Links — это удобный способ открывать контент вашего приложения прямо из веб-ссылок. Они обеспечивают более плавный пользовательский опыт и упрощают обмен контентом.
🔹 На вашем сервере должен быть доступен файл apple-app-site-association в формате JSON.
🔹 В нём указываются appID вашего приложения и разрешённые пути (paths).
{
"applinks": {
"details": [
{
"appID": "TEAMID.hardworker.it",
"paths": [
"/shop",
"/card",
"/profile"
]
}
]
}
}
Где appID указывается в формате teamId.bundleId. paths содержит пользовательские пути, которые должны обрабатываться в приложении.
🔹 Добавьте Associated Domains в Capabilities.
🔹 Укажите ваш домен с префиксом applinks:, например:
applinks:your-domain.com
🔹 Откройте ссылки на реальном устройстве (в Notes, Safari, через сообщения или Telegram).
🔹 Иногда требуется переустановка приложения или перезагрузка устройства, чтобы изменения вступили в силу.
Ожидается обработка следующих ссылок:
https://your-domain.com/shop
https://your-domain.com/card
https://your-domain.com/profile
Universal Links делают навигацию удобнее, а ваш сервис — доступнее.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27❤9🔥5 2🙏1
Недавно Дэвид Ханссон (создатель Ruby on Rails) в интервью Лексу Фридману раскрыл два ключевых критерия при найме:
🔹 Качество кода в тестовом задании.
🔹 Мотивационное письмо.
Казалось бы — ничего нового. Но давайте разберём, почему именно эти пункты стали критически важными в 2025 году.
С появлением ИИ ассистентов вроде GitHub Copilot и ChatGPT работодатели стали скептически относиться к идеально написанным, но безликим решениям.
🔹 Стиль кода (если он похож на шаблонный код от ИИ — это красный флаг).
🔹 Неочевидные решения (вас обязательно спросят: «Почему выбрали именно это решение?»).
🔹 Коммиты (история изменений показывает ход ваших мыслей).
В 2025 году резюме без сопроводительного письма — как код без комментариев: вроде бы всё понятно, но чего-то не хватает. HR-ы и тимлиды признаются: «Письмо решает, кого пригласить, когда 100+ кандидатов с одинаковым опытом».
🔸 Показывает вашу человечность: ИИ пишет резюме, но не может искренне объяснить, почему вы мечтаете работать в этой компании.
🔸 Раскрывает soft skills: Удалённая работа требует чёткой письменной коммуникации.
🔸 Компенсирует недостатки резюме: Нет коммерческого опыта или пробелы в резюме? Расскажите о причинах и пет проектах.
🔹 Персонализация: общие письма для всех компаний не работаю, нужна привязка к конкретной компании, куда вы откликаетесь.
🔹 Почему вы? Привяжите свой опыт к конкретной боли компании, которую необходимо решить.
🔹 Почему они? Докажите что вы реально заинтересованы в работе в данной компании, знакомы с ее историей, пользуетесь их продуктами и знакомы с технологиям, которые в ней используются.
Хорошее письмо — это ваш голос в тишине. В 2025 году его отсутствие равноценно фразе «Мне всё равно, куда устраиваться».
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20👍16🔥9👀1 1
Swift предлагает удобные протоколы для преобразования объектов в JSON и обратно. Разберём, как это работает.
🔹 Decodable: только декодирование (JSON → объект).
🔹 Encodable: только кодирование (объект → JSON).
🔹 Codable: и то, и другое (typealias для Decodable & Encodable).
struct User: Codable {
var name: String
var age: Int
}
Используем JSONDecoder:
let json = """
{
"name": "Иван",
"age": 30
}
"""
guard let jsonData = json.data(using: .utf8) else { return }
do {
let user = try JSONDecoder().decode(User.self, from: jsonData)
print(user.name) // "Иван"
} catch {
print("Ошибка: \(error)")
}
🔸 Имена свойств должны совпадать с ключами JSON (или использовать CodingKeys).
🔸 Типы данных должны соответствовать.
Используем JSONEncoder:
let user = User(name: "Мария", age: 25)
do {
let jsonData = try JSONEncoder().encode(user)
let jsonString = String(data: jsonData, encoding: .utf8)
print(jsonString ?? "")
// {"name":"Мария","age":25}
} catch {
print("Ошибка: \(error)")
}
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // Красивый вывод
encoder.dateEncodingStrategy = .iso8601 // Формат даты
Если имена в JSON не совпадают со свойствами:
struct Product: Codable {
var productName: String
var price: Double
enum CodingKeys: String, CodingKey {
case productName = "product_name_title"
case price
}
}
JSON:
{
"user": {
"name": "Анна",
"age": 28
}
}
Swift:
struct Response: Codable {
var user: User
}
struct User: Codable {
var name: String
var age: Int
}
struct Profile: Codable {
var name: String
var bio: String? // Опциональное поле
}
Если поля нет в JSON, свойство получит значение nil.
Пропускаем ненужные свойства:
struct Settings: Codable {
var theme: String
var fontSize: Int
// Не включаем в Codable
var temporaryFlag: Bool = false
}
Для сложных случаев можно реализовать методы вручную:
struct Custom: Codable {
var id: UUID
var tags: [String]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
tags = try container.decode([String].self, forKey: .tags)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(tags, forKey: .tags)
}
}
🔸 Используйте Codable для большинства задач.
🔸 Настраивайте сложные случаи через CodingKeys.
🔸 Для нестандартных форматов реализуйте методы вручную.
Теперь вы легко сможете работать с любым JSON в Swift!
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤26🙏19👍5 1 1
Компания Apple анонсировала новый Retention Messaging API, который поможет разработчикам снизить отток подписчиков. Теперь можно гибко настраивать сообщения для пользователей, которые хотят отменить подписку.
С помощью данного API можно показывать 4 типа сообщений:
🔹 Текстовое: напоминание о преимуществах подписки.
🔹 Текст + изображение: визуальное убеждение.
🔹 Смена тарифа: предложение перейти на другой тарифный план.
🔹 Промо-оффер: скидка или спецусловия.
Сообщения можно адаптировать под локализацию и продукт, а также менять в реальном времени через серверные запросы.
🔸 Пользователь нажимает «Отменить подписку».
🔸 Система запрашивает у вашего сервера подходящее сообщение (или использует стандартное).
🔸 Пользователь видит предложение: оставить подписку, перейти на другой тариф или воспользоваться скидкой.
🔹 Загрузите тексты и изображения в App Store Connect.
🔹 Настройте дефолтные сообщения (текст, либо текст + картинка).
🔹 Реализуйте серверный endpoint для динамического выбора сообщений.
Retention Messaging API — это не просто новая фича, а стратегический инструмент для монетизации. Вместо пассивного наблюдения за оттоком подписчиков вы получаете:
🔸 Контроль над последним touchpoint перед отменой.
🔸 Данные для анализа поведения пользователей.
🔸 Рычаг влияния на ключевое бизнес-метрики.
Теперь ваша реакция на отток — не постфактум, а в момент принятия пользователем решения.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤26🔥19👍8 3
Очень интересный канал про IOS разработку 👉 @error_nil, в основном все в формате видеоуроков, много полезного материала, интересные обсуждения, XCode проекты и тд, советую подписаться 👍
👍10❤4😁3🔥1🤔1
С выходом Swift Testing многие задумались о миграции с XCTest. Но так ли всё гладко, как обещает Apple? Давайте разберём реальные подводные камни и лайфхаки для перехода.
🔹 XCTest: использует XCTestCase + Objective-C runtime.
🔹 Swift Testing: макросы
@Test + Swift ориентированный подход.🔹 XCTest: выполняется последовательно (один за другим).
🔹 Swift Testing: выполняется параллельно (каждый тест в отдельной Task).
Разница в коде:
// XCTest
func testLogin() { XCTAssertEqual(result, expected) }
// Swift Testing
@Test func login() { #expect(result == expected) }
Swift Testing требует, чтобы проверки (
#expect) выполнялись только внутри Task.// Старая схема (XCTest)
func testAsync() {
DispatchQueue.main.async {
XCTAssertEqual(result, 42)
}
}
// Неправильная миграция (упадёт в Swift Testing)
@Test func asyncTest() {
DispatchQueue.main.async {
#expect(result == 42) // Ошибка: вне контекста Task
}
}
// Правильная миграция
@Test func asyncTest() async { // 1. Объявляем async тест
let result = await withCheckedContinuation { continuation in
DispatchQueue.main.async {
continuation.resume(returning: 42) // 2. Возвращаем результат в контекст Task
}
}
#expect(result == 42) // 3. Проверяем УЖЕ внутри Task-контекста
}
Ключевые моменты:
🔸 Тест должен быть async — это автоматически создаёт контекст Task.
🔸 Все асинхронные операции, которые не поддерживают async/await оборачиваются в withCheckedContinuation.
🔸
#expect вызывается после получения результата, но внутри области теста.Параллельное выполнение тестов могут вызвать гонки данных.
actor Counter {
var count = 0
func increment() {
count += 1
}
}
@Test func testA() async {
await Counter.shared.increment()
#expect(await Counter.shared.count == 1) // Может упасть, если testB запустится раньше!
}
@Test func testB() async {
await Counter.shared.increment()
}Использование
@Suite(.serialized) для последовательного выполнения:@Suite(.serialized)
struct CriticalTests {
@Test func testA() {
}
@Test func testB() {
}
}
В XCTest можно было наследовать XCTestCase и автоматически получать все тесты родителя. В Swift Testing так не работает — тесты нужно дублировать.
Что делать:
🔸 Для простых сценариев использовать параметризованные тесты.
🔸 Для сложных, пока оставьте XCTest и мигрируйте постепенно.
На Swift Testing стоит переходить если у вас современный проект, который использует Swift Concurrency и вам необходимо параллельное выполнение тестов.
Мой совет: Начинайте с гибридного подхода — подключайте Swift Testing для новых модулей, а старые тесты оставляйте в XCTest.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤26👍19 3🔥2
Друзья, привет! Давайте поговорим о том, как мы сами иногда мешаем своей карьере в разработке. Я замечал это и на себе, и на других — есть пять типичных ошибок, которые тормозят рост.
«Сначала изучу весь SwiftUI, потом начну писать код» — знакомо?
Вспоминаю, как сам начинал: вместо того чтобы бесконечно изучать теорию, я просто пробовал писать код. Да, он был кривой, да, с ошибками, но это работало! Сейчас многие застревают на этапе «сначала выучу всё идеально, потом начну». Так не бывает. Лучший способ научиться: делать, ошибаться и исправлять.
«Мой друг-джун сказал, что VIPER — это мусор».
Когда я только начинал, один «опытный» знакомый уверял меня, что Swift — это модно только для мажоров, а за Java будущее и он будет использоваться везде вечно. Хорошо, что я не поверил. Часто советы дают те, кто сам ещё мало что понимает. Ищите советов среди тех, кто реально добился результатов в вашей сфере.
«Мой код идеален, это тимлид ничего не понимает!»
Да, неприятно, когда говорят, что твой код плох. Но именно так и растёшь! Я научился воспринимать замечания не как личное оскорбление, а как бесплатный урок. Заводил даже отдельный блокнот, куда записывал все конструктивные замечания — очень помогает не наступать на те же грабли.
«Сегодня устал, завтра начну».
Сколько раз вы откладывали изучение новой технологии, потому что «еще есть время»? Или обещали себе дописать пет проект, но в итоге смотрели сериалы? Я сам через это проходил. Правда в том, что идеального момента не будет никогда. Каждый отложенный месяц — это упущенные возможности, проекты и даже зарплата. Технологии меняются быстрее, чем мы собираемся их изучить.
«Лучше синица в руках, чем журавль в небе. Останусь там, где хоть что-то платят».
🔹 Страх сменить проект: «а если новый окажется хуже».
🔹 Боязнь попросить повышение: «а вдруг откажут».
🔹 Страх откликнуться на интересную вакансию: «там же нужно будет учить новое!».
Я сам больше года не решался сменить работу, потому что был страх неопределенности, хотя все вокруг на рынке зарабатывали больше меня и работали над современными, интересными проектами.
Эти страхи кажутся разумными только в нашей голове. Со стороны они выглядят именно тем, чем и являются — отговорками, которые мешают нам расти.
В IT безопаснее прыгнуть в неизвестность, чем оставаться в зоне комфорта. Каждый раз, когда вы говорите «еще не готов», кто-то другой говорит «да» и получает ваши потенциальные бенефиты.
Главное, что я понял: карьера строится не на гениальных озарениях, а на постоянных итерациях: попробовал, получил фидбек, исправил, повторил. Чем чаще этот цикл, тем быстрее рост.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤26👍16👀2🔥1🗿1 1
🎨 Вышли официальные наборы компонентов дизайна iOS 26 и iPadOS 26.
Все обновленные компоненты и гайды доступны на сайте Apple.
🤔 Что внутри?
🔹 UI Kit (Figma, Sketch).
🔹 App Icon Template (Sketch, Photoshop, Illustrator, Figma).
➡️ Подписаться на канал
Мобильный трудоголик
Все обновленные компоненты и гайды доступны на сайте Apple.
🔹 UI Kit (Figma, Sketch).
🔹 App Icon Template (Sketch, Photoshop, Illustrator, Figma).
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍3👀1🗿1 1
В Swift существует несколько способов защиты данных от гонки (data races): NSLock, DispatchSemaphore, последовательные очереди (DispatchQueue). Но на WWDC24 компания Apple представила новый Synchronization Framework, включающий современный Mutex – стандартизированную блокировку взаимного исключения.
🔸 Lock: общее название механизмов синхронизации (например, NSLock, os_unfair_lock).
🔸 Mutex: частный случай блокировки, гарантирующий, что только один поток может владеть ресурсом в данный момент.
🔹 Строгое владение – разблокировать может только тот поток, который заблокировал.
🔹 Поддержка Sendable, что делает его удобным для Swift Concurrency.
Пример защиты счетчика:
final class Counter {
private let count = Mutex<Int>(0) // Обернули значение в Mutex
var currentCount: Int {
count.withLock { $0 } // Безопасное чтение
}
func increment() {
count.withLock { $0 += 1 } // Атомарная операция
}
func decrement() throws {
try count.withLock {
guard $0 > 0 else { throw Error.reachedZero }
$0 -= 1
}
}
}
🆚 Mutex vs Actor.
🔸 Actor: идеален для асинхронного доступа, но требует await.
🔸 Mutex: синхронный, подходит для legacy кода или когда нельзя использовать async/await.
🔸 Нужна мгновенная синхронная блокировка.
🔸 Работа с не Sendable типами (например NSBezierPath).
🔸 Интеграция с кодом, не поддерживающим Concurrency.
🔹 Доступен с iOS 18 и macOS 15.
🔹 Не заменяет Actor, а дополняет инструментарий для работы с многопоточностью.
Mutex из Synchronization Framework – это современный, безопасный и эффективный способ защиты данных в Swift.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21🔥11 4❤1🗿1 1