🐳 Container: Linux-контейнеры на macOS без Docker.
Один из самых интересных анонсов WWDC25 — Container, новый инструмент для работы с Linux-контейнерами прямо на macOS. Больше не нужен Docker — теперь можно собирать, запускать и деплоить контейнеры нативно, используя Swift и Virtualization.framework.
⚠️ Что умеет Container:
🔸 Собирает OCI-совместимые образы (как Docker).
🔸 Работает на Apple Silicon (M1/M2/M3 и новее).
🔸 Поддерживает кросс-компиляцию (например, под amd64 для
🔸 Интегрируется с удалёнными реестрами (Docker Hub,
✅ Сборка и деплой Vapor-приложения:
1️⃣ Установка.
Установим Container через Homebrew:
2️⃣ Сборка образа.
Допустим, у нас есть Vapor-приложение. Container умеет читать Dockerfile:
3️⃣ Локальный запуск.
Проверим IP контейнера:
4️⃣ Деплой на
Сначала аутентифицируемся:
Собираем образ под amd64 (
Пушим и деплоим:
🤔 Зачем это iOS-разработчику?
🔹 Тестирование: быстро поднимать моки API, базы данных.
🔹 CI/CD: изолированные среды для SwiftLint, Fastlane.
🔹 Воспроизведение багов: запуск специфичных версий окружения.
🔹 Обучение: новички могут развернуть среду за минуты.
❌ Текущие ограничения:
🔸 Только Apple Silicon.
🔸 Долгая сборка под amd64 (~15-20 минут).
🔸 Нет аналога Docker Compose (но уже есть сторонние решения).
💡 Вывод:
Пока одни спорят, нужны ли контейнеры мобильным разработчикам, другие уже автоматизируют процессы, тестируют идеи и экономят часы работы.
Container — это не просто замена Docker. Это шаг к универсальности Swift-разработки, где один язык и экосистема работают на всех уровнях — от iOS до бэкенда.
➡️ Подписаться на канал
Мобильный трудоголик
Один из самых интересных анонсов WWDC25 — Container, новый инструмент для работы с Linux-контейнерами прямо на macOS. Больше не нужен Docker — теперь можно собирать, запускать и деплоить контейнеры нативно, используя Swift и Virtualization.framework.
🔸 Собирает OCI-совместимые образы (как Docker).
🔸 Работает на Apple Silicon (M1/M2/M3 и новее).
🔸 Поддерживает кросс-компиляцию (например, под amd64 для
Fly.io).🔸 Интегрируется с удалёнными реестрами (Docker Hub,
Fly.io и др.).Установим Container через Homebrew:
brew install container
container system start # Запускаем сервисы
Допустим, у нас есть Vapor-приложение. Container умеет читать Dockerfile:
container build --tag my-app --file Dockerfile .
container run my-app
Проверим IP контейнера:
container list
Fly.ioСначала аутентифицируемся:
container registry login registry.fly.io
Собираем образ под amd64 (
Fly.io не поддерживает arm): container build --tag registry.fly.io/my-app:latest --arch amd64 --file Dockerfile .
Пушим и деплоим:
container images push registry.fly.io/my-app:latest
fly deploy --image registry.fly.io/my-app:latest
🔹 Тестирование: быстро поднимать моки API, базы данных.
🔹 CI/CD: изолированные среды для SwiftLint, Fastlane.
🔹 Воспроизведение багов: запуск специфичных версий окружения.
🔹 Обучение: новички могут развернуть среду за минуты.
🔸 Только Apple Silicon.
🔸 Долгая сборка под amd64 (~15-20 минут).
🔸 Нет аналога Docker Compose (но уже есть сторонние решения).
Пока одни спорят, нужны ли контейнеры мобильным разработчикам, другие уже автоматизируют процессы, тестируют идеи и экономят часы работы.
Container — это не просто замена Docker. Это шаг к универсальности Swift-разработки, где один язык и экосистема работают на всех уровнях — от iOS до бэкенда.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28❤11🔥3👀1 1
Привет, друзья! Сегодня поговорим о XML — формате, который десятилетиями остаётся фундаментом для обмена данными, несмотря на популярность JSON. В мобильной разработке он встречается чаще, чем кажется!
🔸 AndroidManifest.xml (основной файл конфигурации приложений на Android).
🔸 info.plist (аналог в iOS, хотя формально это не XML, но схожая структура).
В Android строки хранятся в strings.xml — это стандартный подход для поддержки множества языков.
В Android XML до сих пор основной язык для разметки экранов (хотя Jetpack Compose постепенно меняет это).
Некоторые API (особенно в корпоративном секторе) до сих пор используют XML вместо JSON.
Например, Firebase Realtime Database поддерживает экспорт/импорт данных в XML.
🔹 Стандартизация: идеален для строгих форматов (например, банковские транзакции).
🔹 Валидация: можно проверить структуру через XSD-схемы.
🔹 Читаемость: вложенность тегов делает данные понятными для человека.
🔹 Поддержка: работает на любом устройстве и ОС без дополнительных библиотек.
🔸 Громоздкость: больше символов, чем в JSON.
🔸 Сложность парсинга: требует больше ресурсов (но XMLParser в iOS и XmlPullParser в Android решают эту проблему).
🔸 Не для всего: не подходит для высоконагруженных real-time-приложений.
XML — не «устаревший» формат, а инструмент для конкретных задач. Он остаётся важным форматом в мобильной разработке, особенно для Android-манифестов, локализации и работы с legacy-API. Несмотря на популярность JSON, его строгая структура и валидация делают XML незаменимым в корпоративных и банковских решениях.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25👀12🗿2❤1🔥1😁1
SwiftUI предлагает несколько подходов к организации навигации и с выходом iOS 16 многое изменилось. Разберём ключевые стратегии, которые помогут вам создавать гибкие и поддерживаемые приложения.
Самый простой способ — NavigationLink:
List(customers) { customer in
NavigationLink {
CustomerDetailScreen(customer: customer)
} label: {
Text(customer.name)
}
}
Минус: инициализация CustomerDetailScreen происходит для каждого элемента списка.
Альтернатива: navigationDestination:
List(customers) { customer in
NavigationLink(customer.name, value: customer)
}
.navigationDestination(for: Customer.self) { customer in
CustomerDetailScreen(customer: customer)
}
Плюс: более эффективно, так как обработка навигации централизована.
Используйте enum для управления сложными сценариями:
enum Route: Hashable {
case dashboard
case detail(Customer)
}
@State private var routes: [Route] = []
NavigationStack(path: $routes) {
Button("Login") {
routes.append(.dashboard) // Программный переход
}
.navigationDestination(for: Route.self) { route in
switch route {
case .dashboard: DashboardView()
case .detail(let customer): CustomerDetailScreen(customer: customer)
}
}
}
🔹 После асинхронных операций (например авторизации).
🔹 Для глубоких ссылок (deeplinks).
Чтобы избежать передачи routes через всю иерархию, вынесите логику в Observable класс:
@Observable
class Router {
var routes: [Route] = []
func navigate(to route: Route) {
routes.append(route)
}
}
// В корневом View:
.environment(Router())
🔹 Доступ к навигации из любого места.
🔹 Чистый код без проброса состояний.
Вдохновляемся React и создаём свой navigate:
struct NavigateAction {
let action: (Route) -> Void
func callAsFunction(_ route: Route) {
action(route)
}
}
// Использование:
@Environment(\.navigate) private var navigate
Button("Войти") {
navigate(.dashboard)
}
🔸 Интуитивный синтаксис.
🔸 Подходит для сложных сценариев.
Каждая вкладка должна иметь свой NavigationStack:
enum AppScreen: Hashable {
case patients, doctors
}
TabView {
PatientsScreen()
.tabItem {
Label("Пациенты", systemImage: "heart")
}
DoctorsScreen()
.tabItem {
Label("Врачи", systemImage: "stethoscope")
}
}
🔸 Не используйте общий Router для вкладок.
🔸 Каждый NavigationStack управляет своим стеком.
Модальные окна — это не часть стека навигации. Для них лучше использовать
@State или отдельный сервис:
.sheet(isPresented: $showModal) {
ModalView()
}
🔹 Для простых приложений — NavigationLink или navigationDestination.
🔹 Для сложных сценариев — глобальный Router + enum маршруты.
🔹 Для вкладок — отдельные NavigationStack на каждую вкладку.
Главное: не усложняйте архитектуру раньше времени. Начинайте с простого и масштабируйте по мере роста приложения.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍28🔥14❤4 2 1
Всем привет! Сегодня хочу обсудить важную тему: почему умения писать качественный код недостаточно, чтобы быть ценным разработчиком.
Бизнесу нужны результаты, а не строки кода. Можно написать идеальную архитектуру, но если она не решает реальную проблему компании — это пустая трата времени.
Пример из практики:
Команда месяц разрабатывала сложный файловый менеджер для загрузки изображений, а потом выяснилось, что пользователи (админы) просто заливают файлы через FTP. Код был безупречным, но абсолютно бесполезным.
🔹 Прежде чем писать код, спросите: «Зачем это нужно?».
🔹 Если не понимаете цель — уточняйте! Иначе рискуете сделать лишнее.
🔹 Бизнесу часто нужен простой и быстрый фикс, а не «идеальная архитектура» которая займет месяцы разработки.
🔹 Решайте сначала то, что влияет на прибыль, а не то, что интересно технически.
🔹 Лучший код — тот, который не написан.
🔹 Иногда проще изменить процесс, чем автоматизировать бесполезный функционал.
Разработчиков ценят не за знание фреймворков, а за:
🔸 Умение решать реальные проблемы.
🔸 Надежность (попадание в сроки).
🔸 Понимание бизнес-метрик.
Хороший код — это лишь инструмент, а настоящая ценность разработчика в умении решать бизнес-задачи. Если ваш код не приносит прибыль, экономит время или улучшает пользовательский опыт, он бесполезен, каким бы элегантным ни был.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24👀14❤7🔥2 1
@MainActor в Swift: как избежать багов с UI.Сегодня разберём
@MainActor — один из самых важных атрибутов для iOS-разработки, который спасает от случайных крашей при обновлении интерфейса.@MainActor?🔸 Маркер, гарантирующий выполнение кода в главном потоке.
🔸 Обязательное требование для всех операций с UI в SwiftUI/UIKit.
🔸 Часть системы акторов (Swift Concurrency).
Автоматическая диспетчеризация.
Помеченный код всегда выполняется на главном потоке:
@MainActor
func updateUI() {
label.text = "Обновлено!" // Безопасное обновление UI
}
Для классов.
Можно пометить весь класс, если он работает с интерфейсом:
@MainActor
class UserProfileViewModel: ObservableObject {
@Published var name: String = "" // Изменения в главном потоке
}
@MainActor.
Task {
let data = await loadData() // Фоновое выполнение
titleLabel.text = data.title // Краш: попытка обновить UI не из главного потока
}
Task {
let data = await loadData()
await MainActor.run { // Переключение на главный поток
titleLabel.text = data.title
}
}
body уже на главном потоке.
Нет нужды дополнительно маркировать:
struct ContentView: View {
var body: some View { // Автоматически @MainActor
...
}
}
MVVM и ObservableObject.
Лучше явно пометить ViewModel при помощи
@MainActor:
@MainActor
class SettingsViewModel: ObservableObject {
@Published var theme: Theme = .light
}
@MainActor — это важный инструмент для безопасной работы с UI, который автоматически гарантирует выполнение кода в главном потоке. Он особенно полезен в SwiftUI и UIKit, предотвращая случайные краши при обновлении интерфейса из фоновых задач.Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤25👍14 4 2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
С выходом SF Symbols 7 работать с анимацией иконок стало проще, чем когда-либо. Apple добавила мощные API, которые открывают новые возможности для визуальных эффектов.
🔹 Draw On / Draw Off:
Теперь можно анимировать появление и исчезновение символа постепенно, штрих за штрихом. Это создаёт плавные и стильные переходы — идеально для интерактивных элементов интерфейса.
🔹 Progress Draw:
Анимация на основе variableValue позволяет «прорисовывать» символ в зависимости от прогресса. Например, можно визуализировать загрузку, заполнение или поэтапное выполнение задачи.
🔹 Magic Replace:
Плавные переходы между связанными символами стали ещё умнее. Теперь замена иконок выглядит естественно, без резких скачков — будто одна форма превращается в другую.
🔹 Gradients:
Новый режим отрисовки с градиентами добавляет глубину и акцент. Иконки выглядят более выразительно, особенно в сочетании с анимацией.
Новые фичи в SF Symbols 7 позволяют создавать более динамичные и приятные интерфейсы без сложного кода.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍23❤11🔥1 1 1
Привет, друзья! Сегодня разберём Strategy — мощный паттерн, который позволяет менять поведение объекта на лету без тонны условных выражений if/else.
🔸 Выносим разные алгоритмы в отдельные классы.
🔸 Основной объект делегирует работу этим алгоритмам.
🔸 Можно подменять логику прямо во время выполнения.
🔸 Зависим от протокола, а не от конкретного класса.
Допустим, у нас есть персонаж, который может:
🔹 Ходить.
🔹 Бегать.
🔹 Летать.
Вместо простой реализации:
enum Movement {
case walk, run, fly
}
class Character {
func move(type: Movement) {
switch type {
case .walk: print("Идёт")
case .run: print("Бежит")
case .fly: print("Летит")
}
}
}
Напишем элегантно через Strategy:
protocol MovementStrategy {
func move()
}
class WalkStrategy: MovementStrategy {
func move() { print("Идёт пешком") }
}
class FlyStrategy: MovementStrategy {
func move() { print("Летит на реактивном ранце") }
}
class GameCharacter {
private var strategy: MovementStrategy
init(strategy: MovementStrategy) {
self.strategy = strategy
}
func setStrategy(_ strategy: MovementStrategy) {
self.strategy = strategy
}
func performMove() {
strategy.move()
}
}
// Использование
let hero = GameCharacter(strategy: WalkStrategy())
hero.performMove() // Идёт пешком
hero.setStrategy(FlyStrategy())
hero.performMove() // Летит на реактивном ранце
🔹 Гибкость: новые стратегии добавляются без изменения основного класса.
🔹 Тестируемость: можно подменять реальные стратегии моками, проверяя логику изолированно.
🔹 Чистый код: нет гигантских switch-блоков.
Паттерн Strategy делает код гибким и чистым, позволяя менять поведение объекта на лету без условных конструкций. Он идеально подходит для сценариев, где нужно быстро добавлять новые алгоритмы или тестировать разные варианты поведения через моки.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20❤6👍1 1 1
После десятков собеседований и внезапных офферов приходит осознание: программирование — это не просто работа. Вот что делает эту профессию особенной:
Каждый день — новые квесты:
🔹 Баги = спрятанные сундуки с сокровищами.
🔹 Сложные задачи = боссы, которых нужно победить.
🔹 Релизы = пройденные уровни с наградами.
Когда твой код используют миллионы:
🔹 Видишь результат своей работы в реальном мире.
🔹 Осознаешь свою значимость (это круче, чем цифры на счете).
🔹 Получаешь фидбек от живых пользователей.
IT дает то, чего нет во многих профессиях:
🔹 Возможность работать из любой точки мира.
🔹 Гарантированный спрос на навыки.
🔹 Финансовую подушку даже в кризисы.
🔹 Государственное признание: IT-специалисты получают льготные ипотеки, налоговые послабления и поддержку на государственном уровне как стратегически важная профессия.
🔹 Уважение среди других профессий: врачи, инженеры и представители других сложных специальностей открыто признают, что программирование требует уникального сочетания навыков и действительно трудозатратно.
🔹 Социальный капитал: в глазах общества IT-специалист автоматически получает статус умного и перспективного человека, что заметно даже в бытовых ситуациях.
🔹 Культурный статус: в кино, сериалах и СМИ образ программиста давно стал синонимом интеллекта и успеха, формируя особое восприятие профессии в массовом сознании.
🔹 Финансовая стабильность: даже junior-специалисты получают зарплаты выше среднего по рынку, а опытные разработчики могут выбирать среди предложений с шестизначными цифрами.
🔹 Влияние на будущее: разработчики напрямую участвуют в создании технологий, которые меняют мир, от медицинских решений до космических программ.
🔹 Новые технологии каждые полгода (никогда не будет скучно).
🔹 Возможность решать задачи, которые еще вчера казались невозможными.
🔹 Ощущение прогресса, когда оглядываешься на свой код годовой давности.
🔹 IT-тусовки и митапы, где все говорят на одном языке.
🔹 Возможность находить работу через знакомых.
🔹 Общий мемный культурный код.
Мы получаем деньги за то, что решаем интересные головоломки — это же мечта любого ребенка!
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22❤8 3🔥2🤔2🤝1 1
Как разработчику не застрять в поиске работы на месяцы
Часто вижу, как сильные специалисты месяцами ищут работу без оффера.
Обычно дело не в рынке, а в резюме, LinkedIn и стратегии поиска.
У моего коллеги, карьерного консультанта, на канале как раз об этом:
— как переписать резюме так, чтобы оно приносило интервью
— как оживить LinkedIn и GitHub
— как строить стратегию поиска, а не хаотично откликаться
Если вы в поиске или хотите подготовиться к нему заранее, рекомендую заглянуть.
👉 https://t.me/bezpanikiIT
Часто вижу, как сильные специалисты месяцами ищут работу без оффера.
Обычно дело не в рынке, а в резюме, LinkedIn и стратегии поиска.
У моего коллеги, карьерного консультанта, на канале как раз об этом:
— как переписать резюме так, чтобы оно приносило интервью
— как оживить LinkedIn и GitHub
— как строить стратегию поиска, а не хаотично откликаться
Если вы в поиске или хотите подготовиться к нему заранее, рекомендую заглянуть.
👉 https://t.me/bezpanikiIT
This media is not supported in your browser
VIEW IN TELEGRAM
В Xcode 26 есть возможность попросить ИИ быстро внести изменения в код!
Пока работает только на macOS Tahoe Beta, но выглядит многообещающе.
➡️ Подписаться на канал
Мобильный трудоголик
Пока работает только на macOS Tahoe Beta, но выглядит многообещающе.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤23🔥6 4👍1 1
Вы когда-нибудь задумывались, как на самом деле работает switch-case в Swift? Под капотом он использует малоизвестный, но мощный оператор ~=, который отвечает за сравнение значений.
Это бинарный оператор, который возвращает true, если значения совпадают. По умолчанию он просто сравнивает два значения, но его можно перегружать для кастомной логики.
let range = 1..<10
print(5 ~= range) // true потому что 5 входит в диапазон
print(15 ~= range) // false
Давайте создадим свой тип и реализуем для него pattern matching:
protocol Matchable {
var matchKey: String { get }
}
struct User: Matchable {
let email: String
var matchKey: String { email }
}
// Перегружаем оператор ~=
func ~=(pattern: String, value: Matchable) -> Bool {
return value.matchKey == pattern
}
let user = User(email: "test@test.com")
switch user {
case "test@test.com": // Теперь работает благодаря нашему оператору
print("Привет, тестировщик!")
default:
print("Неизвестный пользователь")
}
// Выведет: Привет, тестировщик!
🔹 Для сравнения сложных структур.
🔹 При работе с кастомными типами в switch-case.
🔹 Для создания выразительных условий в if-else.
Оператор ~= мощный инструмент для кастомного сравнения значений, который особенно полезен при работе с собственными типами в конструкциях switch и if. Его перегрузка позволяет создавать выразительный и гибкий код, адаптированный под конкретные задачи.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🔥12❤4 3 1
Знакомо чувство, когда проект превращается в кошмар из багов и бесконечных правок? Говнокод — это не просто шутка, а реальная проблема, которая рушит продукты и команды. Вот как распознать и избежать его.
🔸 Не решает задачу: код может работать без ошибок, но быть бесполезным для бизнеса.
🔸 Код пожирает ресурсы: неэффективность, из-за которой растут затраты на инфраструктуру.
🔸 Непонятная структура: даже автор кода через месяц не разберётся, что он делает и как он работает.
🔸 Копипаст: одинаковые баги в 10 местах, которые нельзя исправить одним правкой.
🔸 Глобальные переменные: скрытые зависимости, которые ломают тесты и логику.
🔸 Отсутствие тестов: изменения становятся лотереей, а релизы — русской рулеткой.
🔹 Читаемость: другой разработчик понимает его с первого взгляда.
🔹 Гибкость: легко добавлять функционал и удалять устаревшие части.
🔹 Минимальные зависимости: изменения в одном модуле не ломают всю систему.
🔹 Тесты: юнит-тесты автоматически проверяют, не сломали ли вы уже работающую функциональность.
🔹 Осмысленные имена: переменные и методы называются так, чтобы не требовались комментарии.
🔹 Код-ревью: обязательная проверка кода перед влитием в основную ветку.
🔹 Стандарты разработки: единый стиль для всей команды (длина строк, переносы скобок, форматирование, нейминг).
🔹 Своевременный рефакторинг: постепенное улучшение вместо переписывания с нуля.
🔹 Тесты для багов: пишем тест перед исправлением, чтобы баг не вернулся.
Хороший код — это не про гениальность, а про дисциплину. Даже под жёсткими дедлайнами можно писать поддерживаемый код, если следовать простым правилам.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤23🔥12👍3🗿1 1
Каждая задача (Task) в Swift может иметь свой собственный контекст — локальные данные, доступные ей и её дочерним задачам. Это похоже на ThreadLocal, но для асинхронных задач.
🔸
@TaskLocal: проперти-враппер, который позволяет шарить данные между задачами.🔸 withValue: задаёт значение на время выполнения блока кода.
🔸 Наследование: дочерние задачи (async let, TaskGroup) получают копию контекста родителя.
@TaskLocal static var requestID: String?
func fetchData() async {
print("Request ID:", requestID ?? "unknown") // Доступ к контексту
}
Task {
await $requestID.withValue("123") {
await fetchData() // Выведет "123"
}
await fetchData() // Выведет "unknown" так как контекст сброшен
}
🔹 Хранилище: словарь стеков (каждый ключ — свой стек значений).
🔹 withValue пушит значение в стек, defer — удаляет после выполнения.
🔹 Sendable-типы: гарантируют потокобезопасность.
🔸 Не для больших данных: только для легковесного контекста (ID, флаги).
🔸 Изменяемые объекты: если передаёте класс, изменения будут видны во всех задачах.
Task Local отлично подходит для передачи контекстных данных в асинхронных операциях — например, для логирования ID запросов, управления настройками выполнения или отладки цепочек задач. Главное помнить, что это инструмент для легковесных данных, а не для сложных изменяемых объектов.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤21 12👍4🔥2🙏2
Кэширование — мощный инструмент, который почему-то часто упускают из виду. А ведь это идеальное решение для временного хранения данных без лишних запросов к сети или базе.
NSCache — встроенный в iOS механизм кэширования, который автоматически освобождает память при нехватке ресурсов. Но есть нюанс: он работает только с классами, наследующими NSObject.
Решение: обертка вокруг NSCache, которая позволяет использовать любые типы данных, включая структуры.
final class Cache<Key: Hashable, Value> {
private let wrapped = NSCache<WrappedKey, Entry>()
// реализация подписки, вставки и удаления
}
Чтобы избежать устаревших данных, добавим автоматическую инвалидацию по времени:
struct Entry {
let value: Value
let expirationDate: Date // Удаляем данные после истечения срока
}
Для оффлайн-доступа к данным расширяем кэш поддержкой Codable и сохраняем в файлы:
extension Cache: Codable where Key: Codable, Value: Codable {
func saveToDisk(name: String) throws {
let data = try JSONEncoder().encode(self)
try data.write(to: cachesDirectory.appendingPathComponent(name))
}
}
🔹 Повторное использование данных (например загруженных товаров в интернет магазине).
🔹 Оффлайн-режим: доступ к последним данным после перезапуска.
🔹 Оптимизация производительности: меньше запросов к серверу.
Кэширование — не просто «сохранить и забыть». Это баланс между скоростью, актуальностью данных и управлением памятью.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤22 11👍1🔥1 1
Технический разбор Max 😎
В канале «Prefire iOS» вышел разбор свежего APK мессенджера Max - и он развеивает многие мифы о «новом и безопасном» приложении.
Что нашли внутри:
- WebRTC для звонков
- ExoPlayer и даже TensorFlow Lite
- следы Odnoklassniki/TamTam (да, привет VK Group 👀)
- и самое главное - никакого E2EE 😬
Без сложных терминов, но с фактами, скринами и кодом.
После такого «прозрачного» взгляда на APK начинаешь совсем по-другому смотреть на работу мессенджеров.
Все подробности и ссылка на Хабр - в посте
В канале «Prefire iOS» вышел разбор свежего APK мессенджера Max - и он развеивает многие мифы о «новом и безопасном» приложении.
Что нашли внутри:
- WebRTC для звонков
- ExoPlayer и даже TensorFlow Lite
- следы Odnoklassniki/TamTam (да, привет VK Group 👀)
- и самое главное - никакого E2EE 😬
Без сложных терминов, но с фактами, скринами и кодом.
После такого «прозрачного» взгляда на APK начинаешь совсем по-другому смотреть на работу мессенджеров.
Все подробности и ссылка на Хабр - в посте
🔥10👀5🗿4😁3👍2 2
Оказывается, некоторые опытные разработчики сознательно скручивают свой опыт в резюме и устраиваются на несколько мидл-позиций вместо одной сеньорской. Вот главные причины этого тренда:
Две мидл-зарплаты часто превышают доход сеньора, особенно если работать на западные компании. Финансовая выгода очевидна.
🔹 Притвориться мидлом на собеседовании.
🔹 Взять задачи под мидла, но делай их со скоростью сеньора.
🔹 Избегать лишних созвонов — говорить что «погружаешься в проект».
🔹 Автоматизировать рутину, использовать ИИ, оценивать задачи в 1.5-2 раза больше по срокам.
На мидл-позициях от тебя не ждут:
🔸 Архитектурных решений.
🔸 Участия в бесконечных созвонах.
🔸 Менторства.
🔸 Высокой ответственности за продукт.
Можно просто брать таски и закрывать их в 2 раза быстрее благодаря реальному опыту.
🔸 Придется работать по 10-12 часов в день.
🔸 Риск пересекающихся митингов.
🔸 Постоянное напряжение от двойной игры.
🔸 Возможность выгорания.
Схема работы «сеньор под прикрытием» может принести краткосрочную финансовую выгоду, но требует постоянного стресса, многозадачности и грозит выгоранием. Это тактический ход, а не стратегия карьеры — подходит только тем, кто готов платить за двойную зарплату своим временем и ментальным здоровьем.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👀18🔥11❤2👍2😁2🗿1
Происходит историческое событие: компания Apple начала переговоры с российскими властями о возможном размещении отечественного магазина приложений RuStore в App Store. Вот что известно на данный момент:
🔸 Неформальные договорённости уже достигнуты: Apple пообещала не блокировать размещение RuStore.
🔸 Переговоры ведутся при участии Минцифры и главы РФПИ Кирилла Дмитриева.
🔸 Технически это реализуемо: опыт ЕС показал, что альтернативные магазины могут работать на iOS.
🔸 Комиссии за установки: как Apple будет получать свою долю за скачивания через RuStore.
🔸 Геоограничения: вероятно, RuStore будет доступен только на территории РФ.
🔸 Техническая интеграция: как будет организован процесс предустановки, установки и обновления приложений.
1 сентября 2025 года — крайний срок для выполнения требований о предустановке российских магазинов приложений на всех смартфонах и планшетах, продаваемых в России.
🔹 В ЕС с марта 2024 года Apple уже позволяет устанавливать альтернативные магазины приложений.
🔹 Российские банки активно заинтересованы в возвращении своих приложений в iOS, так как сейчас они недоступны из-за санкций.
🔹 Технических преград нет, остались юридические и финансовые нюансы.
Я надеюсь, что RuStore скоро появится на iOS, ведь это откроет новые вакансии для разработчиков и даст пользователям долгожданный доступ к банковским и другим приложениям, которые исчезли из App Store из-за санкций.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤18🔥10👍5🙏2👏1👀1
Если вы когда-то спорили с коллегами о том, стоит ли помечать классы final для оптимизации производительности, сохраните эту статью. Она разложит все по полочкам.
Swift использует два принципиально разных подхода:
🔸 Статическая диспетчеризация: быстрая, но менее гибкая.
🔸 Динамическая диспетчеризация: медленнее, зато поддерживает полиморфизм.
Динамическая диспетчеризация может негативно влиять на производительность из-за:
🔸 Потери возможности оптимизации кода.
🔸 Увеличения вероятности кэш-промахов CPU.
🔸 Накладных расходов на поиск метода в таблицах.
Ключевой момент: если компилятор может определить адрес метода на этапе компиляции — используется статическая диспетчеризация. Иначе динамическая.
Встраивание (Inlining):
Компилятор может заменить вызов функции ее телом, чтобы избежать накладных расходов.
func square(_ x: Int) -> Int {
return x * x
}
let result = square(5)
// После оптимизации компилятор может превратить это в:
let result = 5 * 5 // 25 (вычислено на этапе компиляции!)
Прямая диспетчеризация (Direct Dispatch):
Используется для:
🔹 Структур.
🔹 Перечислений.
🔹 final классов.
🔹 static и private методов.
Почему это быстро?
Адрес метода известен заранее: CPU выполняет его за одну инструкцию.
Табличная (Virtual Table):
Каждый класс хранит таблицу методов. При вызове:
🔹 CPU ищет адрес метода в таблице.
🔹 Переходит по нему.
class Animal {
func sound() {
}
}
class Dog: Animal {
override func sound() {
}
}
let pet: Animal = Dog()
pet.sound() // Динамически выбирается Dog.sound()
Протокольная (Witness Table):
Аналогично табличной, но для протоколов:
protocol Drawable {
func draw()
}
struct Circle: Drawable {
func draw() {
}
}
let shape: Drawable = Circle()
shape.draw() // Вызов через witness table
Самая гибкая, но медленная диспетчеризация через Objective-C runtime:
class MyClass: NSObject {
@objc dynamic func message() {
}
}
// Вызов через objc_msgSend
Особенности:
🔹 Позволяет модифицировать поведение методов в runtime (swizzling).
🔹 Используется для KVO, Core Data и совместимости с Objective-C.
🔸 Проблема 1:
protocol P {
}
extension P {
func foo() {
print("Protocol")
}
}
class A: P {
func foo() {
print("Class")
}
}
let instance = A()
instance.foo() // Выведет: Class, динамическая диспетчеризация
let instance2: P = A()
instance2.foo() // Выведет: Protocol, статическая диспетчеризация
Решение проблемы:
protocol P {
func foo() // Добавили метод в протокол
}
extension P {
func foo() {
print("Protocol")
}
}
class A: P {
func foo() {
print("Class")
}
}
let instance = A()
instance.foo() // Выведет: Class, динамическая диспетчеризация
let instance2: P = A()
instance2.foo() // Выведет: Class, динамическая диспетчеризация
🔸 Проблема 2:
protocol P {
func foo()
}
extension P {
func foo() {
print("Protocol")
}
}
class A: P {
}
class B: A {
func foo() {
print("Class")
}
}
let instance = B()
instance.foo() // Выведет: Class
let instance2: A = B()
instance2.foo() // Выведет: Protocol
Решение проблемы:
protocol P {
func foo()
}
extension P {
func foo() {
print("Protocol")
}
}
class A: P {
func foo() { // Нужно реализовать метод
}
}
class B: A {
override func foo() {
print("Class")
}
}
let instance = B()
instance.foo() // Выведет: Class
let instance2: A = B()
instance2.foo() // Выведет: Class
Используйте final и private там, где это возможно, чтобы компилятор мог оптимизировать код. Динамическая диспетчеризация — мощный инструмент, но не всегда нужен. Баланс между гибкостью и производительностью — ключ к эффективному коду.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20🔥16👍2🙏1🫡1 1
Новые Foundation Models от Apple — это не просто ещё один ИИ, а специально обученная модель для работы со Swift и SwiftUI. Рассказываю, как правильно с ней общаться.
🔸 Очень маленький контекст: всего 4096 токенов на всё (и вход и выход).
🔸 Жесткие ограничения безопасности: много ложных срабатываний.
🔸 Заточена под генерацию Swift-структур через Generable.
🔸 Работает полностью на устройстве: не нужен интернет.
Просто создайте Playgrounds.swift в проекте и экспериментируйте:
import Playgrounds
#Playground {
// Тестируйте промты здесь
let prompt = "Напиши функцию на Swift"
}
🔹 Guided Generation: используйте макрос Generable для чёткой структуры ответа.
🔹 Порядок свойств: ИИ генерирует последовательно, поэтому важные поля ставьте первыми.
🔹 Указание длины: пишите «подробно», «кратко», «три предложения» для контроля объёма.
🔹 temperature: 0.8 — более креативные ответы.
🔹 sampling: .greedy — детерминированные и предсказуемые.
🔹 maxTokens: 1000 — ограничение длины ответа.
🔹 Всегда обрабатывайте ошибки LanguageModelError.
🔹 Пользовательский ввод может триггерить защитные механизмы.
🔹 Имейте fallback-стратегии на случай блокировок.
🔹 Нативная интеграция со Swift.
🔹 Не нужно парсить JSON: работаете напрямую с объектами.
🔹 Мгновенное тестирование без API-вызовов.
🔹 Полная конфиденциальность: всё на устройстве.
Apple Foundation Models — это не просто ещё один инструмент ИИ, а качественно новый подход к разработке. Модель, специально обученная для работы со Swift и SwiftUI, позволяет интегрировать интеллектуальные функции напрямую в код — без сложных API, JSON-парсинга и внешних зависимостей. Всё работает локально, безопасно и с полной интеграцией в экосистему Apple.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22👍13 4❤1👀1
Опытные разработчики чаще принимают ИИ-инструменты, чем новички. Возможно, дело в уверенности: сеньоры не боятся что их заменят, а видят в ИИ помощника.
Как работает:
Бросаешь задачу в ChatGPT (или другие ИИ), получаешь готовый код и слегка его правишь.
Проблема:
Нет глубокого понимания кода, ментальная модель не строится.
Когда использовать:
Только для быстрых прототипов и экспериментов.
Риски:
Код может быть неоптимальным и со скытыми багами.
Как работает:
Тщательно проектируешь запросы, задаешь контекст, формат и ограничения, получаешь точный результат.
Преимущество:
Полный контроль над процессом, понимание каждой строки кода.
Идеально для:
Рутинных задач, шаблонного кода и документации.
Аналогия:
Как менторить джуна: даешь четкие инструкции и проверяешь результат.
Vibe-coding: эмоциональный подход «сгенерируй что-нибудь».
Prompt-engineering: инженерный подход «дай мне конкретное решение под мои требования».
🔹 Всегда включать голову: не важно откуда код: из ИИ, Stack Overflow или из статьи.
🔹 Дробить задачи: давать ИИ конкретные мелкие задания вместо «сделай все».
🔹 Тестировать и проверять: любой сгенерированный код требует ревью и тестов.
🔹 Учиться формулировать: прокачивать навык написания четких промтов.
ИИ не замена разработчику, а мощный инструмент. Как молоток: можно собрать мебель, а можно разбить палец. Все зависит от того, кто и как его использует.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22❤15 12🔥3🤔1🙏1
Шокирующая статистика из США: каждый 15-й молодой IT-специалист сейчас без работы. Среди программистов уровень безработицы достигает 7.5% — это выше, чем у гуманитариев и биологов!
🔸 Массовые сокращения в гигантах типа Amazon, Microsoft и Intel.
🔸 Вакансий для джунов стало на 21% меньше.
🔸 Нейросети забирают задачи новичков: код-ревью, тестирование, шаблонный код.
🔸 Переизбыток выпускников: 170K дипломов за год (вдвое больше чем 10 лет назад).
🔸 Индустрия повзрослела: меньше стартапов, больше поддержки легаси.
🔸 Смещение фокуса на senior-специалистов вместо массового найма джунов.
🔸 ИИ-революция: ChatGPT и Copilot заменяют начинающих разработчиков.
🔸 Постковидная коррекция: переоценка штата после бума удалёнки.
🔹 Прокачивать уникальные навыки, а не только один язык программирования и фреймворк.
🔹 Собирать портфолио: пет-проекты, фриланс с реальными кейсами.
🔹 Рассматривать смежные области, которые пока еще не заменит искусственный интеллект.
Рынок труда для новичков в IT серьёзно изменился. Теперь недостаточно просто закончить курсы, нужно предлагать реальную ценность и адаптироваться к новым реалиям.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16👀10🤯5 2🤔1🙏1🗿1