Мобильный трудоголик
1.32K subscribers
61 photos
9 videos
263 links
👨‍💻 Пишу простым языком об iOS разработке на Swift и мобильной разработке в целом.
🔹 Вошел в IT задолго до того как это стало мейнстримом.
---
‍Обо мне: https://t.me/hardworkerIT/3
Чат: @hardworkerChatIT
Канал про разработку и жизнь в ИТ: @itDenisov
Download Telegram
🐳 Container: Linux-контейнеры на macOS без Docker.

Один из самых интересных анонсов WWDC25Container, новый инструмент для работы с Linux-контейнерами прямо на macOS. Больше не нужен Docker — теперь можно собирать, запускать и деплоить контейнеры нативно, используя Swift и Virtualization.framework.


⚠️ Что умеет Container:

🔸 Собирает OCI-совместимые образы (как Docker).
🔸 Работает на Apple Silicon (M1/M2/M3 и новее).
🔸 Поддерживает кросс-компиляцию (например, под amd64 для Fly.io).
🔸 Интегрируется с удалёнными реестрами (Docker Hub, Fly.io и др.).


Сборка и деплой Vapor-приложения:

1️⃣ Установка.

Установим Container через Homebrew:

brew install container
container system start # Запускаем сервисы



2️⃣ Сборка образа.

Допустим, у нас есть Vapor-приложение. Container умеет читать Dockerfile:

container build --tag my-app --file Dockerfile .



3️⃣ Локальный запуск.


container run my-app


Проверим IP контейнера:


container list



4️⃣ Деплой на 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



🤔 Зачем это iOS-разработчику?

🔹 Тестирование: быстро поднимать моки 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
👍2811🔥3👀11
♠️ XML в мобильной разработке: почему он всё ещё актуален?

Привет, друзья! Сегодня поговорим о XML — формате, который десятилетиями остаётся фундаментом для обмена данными, несмотря на популярность JSON. В мобильной разработке он встречается чаще, чем кажется!


🤔 Где XML используется в iOS/Android?

1️⃣ Манифесты и конфиги:

🔸 AndroidManifest.xml (основной файл конфигурации приложений на Android).
🔸 info.plist (аналог в iOS, хотя формально это не XML, но схожая структура).


2️⃣ Локализация:

В Android строки хранятся в strings.xml — это стандартный подход для поддержки множества языков.


3️⃣ Верстка UI:

В Android XML до сих пор основной язык для разметки экранов (хотя Jetpack Compose постепенно меняет это).


4️⃣ Сетевые запросы:

Некоторые API (особенно в корпоративном секторе) до сих пор используют XML вместо JSON.


5️⃣ Базы данных:

Например, Firebase Realtime Database поддерживает экспорт/импорт данных в XML.


Плюсы XML для мобильных разработчиков:

🔹 Стандартизация: идеален для строгих форматов (например, банковские транзакции).
🔹 Валидация: можно проверить структуру через XSD-схемы.
🔹 Читаемость: вложенность тегов делает данные понятными для человека.
🔹 Поддержка: работает на любом устройстве и ОС без дополнительных библиотек.


Минусы XML:

🔸 Громоздкость: больше символов, чем в 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🗿21🔥1😁1
🔢 Навигация в SwiftUI: от основ до продвинутых техник.

SwiftUI предлагает несколько подходов к организации навигации и с выходом iOS 16 многое изменилось. Разберём ключевые стратегии, которые помогут вам создавать гибкие и поддерживаемые приложения.


1️⃣ Базовая навигация.

Самый простой способ — 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)
}


Плюс: более эффективно, так как обработка навигации централизована.


2️⃣ Динамическая маршрутизация.

Используйте 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).


3️⃣ Глобальная маршрутизация.

Чтобы избежать передачи routes через всю иерархию, вынесите логику в Observable класс:

@Observable
class Router {
var routes: [Route] = []

func navigate(to route: Route) {
routes.append(route)
}
}

// В корневом View:
.environment(Router())


Преимущества:
🔹 Доступ к навигации из любого места.
🔹 Чистый код без проброса состояний.


4️⃣ Навигация через Environment Values.

Вдохновляемся React и создаём свой navigate:

struct NavigateAction {
let action: (Route) -> Void

func callAsFunction(_ route: Route) {
action(route)
}
}

// Использование:
@Environment(\.navigate) private var navigate

Button("Войти") {
navigate(.dashboard)
}


⚠️ Почему это удобно:
🔸 Интуитивный синтаксис.
🔸 Подходит для сложных сценариев.


5️⃣ Навигация во вкладках (TabView).

Каждая вкладка должна иметь свой NavigationStack:

enum AppScreen: Hashable {
case patients, doctors
}

TabView {
PatientsScreen()
.tabItem {
Label("Пациенты", systemImage: "heart")
}

DoctorsScreen()
.tabItem {
Label("Врачи", systemImage: "stethoscope")
}
}


⚠️ Важно:
🔸 Не используйте общий Router для вкладок.
🔸 Каждый NavigationStack управляет своим стеком.


6️⃣ Модальные окна и навигация.

Модальные окна — это не часть стека навигации. Для них лучше использовать @State или отдельный сервис:

.sheet(isPresented: $showModal) {
ModalView()
}



💡 Вывод:
🔹 Для простых приложений — NavigationLink или navigationDestination.
🔹 Для сложных сценариев — глобальный Router + enum маршруты.
🔹 Для вкладок — отдельные NavigationStack на каждую вкладку.

Главное: не усложняйте архитектуру раньше времени. Начинайте с простого и масштабируйте по мере роста приложения.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍28🔥14421
👨‍💻 Почему хорошего кода недостаточно для успеха в разработке.

Всем привет! Сегодня хочу обсудить важную тему: почему умения писать качественный код недостаточно, чтобы быть ценным разработчиком.


⚠️ Код ≠ ценность.

Бизнесу нужны результаты, а не строки кода. Можно написать идеальную архитектуру, но если она не решает реальную проблему компании — это пустая трата времени.

Пример из практики:
Команда месяц разрабатывала сложный файловый менеджер для загрузки изображений, а потом выяснилось, что пользователи (админы) просто заливают файлы через FTP. Код был безупречным, но абсолютно бесполезным.


🤔 Что действительно важно?


1️⃣ Понимание бизнес-задачи.

🔹 Прежде чем писать код, спросите: «Зачем это нужно?».
🔹 Если не понимаете цель — уточняйте! Иначе рискуете сделать лишнее.


2️⃣ Приоритеты.

🔹 Бизнесу часто нужен простой и быстрый фикс, а не «идеальная архитектура» которая займет месяцы разработки.
🔹 Решайте сначала то, что влияет на прибыль, а не то, что интересно технически.


3️⃣ Эффективность, а не объем кода.

🔹 Лучший код — тот, который не написан.
🔹 Иногда проще изменить процесс, чем автоматизировать бесполезный функционал.


Как это влияет на карьеру?

Разработчиков ценят не за знание фреймворков, а за:
🔸 Умение решать реальные проблемы.
🔸 Надежность (попадание в сроки).
🔸 Понимание бизнес-метрик.


Хороший код — это лишь инструмент, а настоящая ценность разработчика в умении решать бизнес-задачи. Если ваш код не приносит прибыль, экономит время или улучшает пользовательский опыт, он бесполезен, каким бы элегантным ни был.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24👀147🔥21
🔢 @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
}
}



♣️ Особенности в SwiftUI.

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👍1442🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ Анимируем SF Symbols 7: новые возможности.

С выходом SF Symbols 7 работать с анимацией иконок стало проще, чем когда-либо. Apple добавила мощные API, которые открывают новые возможности для визуальных эффектов.


🔹 Draw On / Draw Off:

Теперь можно анимировать появление и исчезновение символа постепенно, штрих за штрихом. Это создаёт плавные и стильные переходы — идеально для интерактивных элементов интерфейса.

🔹 Progress Draw:

Анимация на основе variableValue позволяет «прорисовывать» символ в зависимости от прогресса. Например, можно визуализировать загрузку, заполнение или поэтапное выполнение задачи.

🔹 Magic Replace:

Плавные переходы между связанными символами стали ещё умнее. Теперь замена иконок выглядит естественно, без резких скачков — будто одна форма превращается в другую.

🔹 Gradients:

Новый режим отрисовки с градиентами добавляет глубину и акцент. Иконки выглядят более выразительно, особенно в сочетании с анимацией.


🔗 Подробнее на сайте Apple


💡 Вывод:

Новые фичи в SF Symbols 7 позволяют создавать более динамичные и приятные интерфейсы без сложного кода.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍2311🔥111
🔢 Паттерны проектирования в Swift: Стратегия.

Привет, друзья! Сегодня разберём 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
🔥206👍111
👨‍💻 Что кроме зарплаты держит нас в IT?

После десятков собеседований и внезапных офферов приходит осознание: программирование — это не просто работа. Вот что делает эту профессию особенной:


1️⃣ Это лучшая игра для взрослых.

Каждый день — новые квесты:
🔹 Баги = спрятанные сундуки с сокровищами.
🔹 Сложные задачи = боссы, которых нужно победить.
🔹 Релизы = пройденные уровни с наградами.


2️⃣ Влияние, которое можно потрогать.

Когда твой код используют миллионы:
🔹 Видишь результат своей работы в реальном мире.
🔹 Осознаешь свою значимость (это круче, чем цифры на счете).
🔹 Получаешь фидбек от живых пользователей.


3️⃣ Стабильность в нестабильном мире.

IT дает то, чего нет во многих профессиях:
🔹 Возможность работать из любой точки мира.
🔹 Гарантированный спрос на навыки.
🔹 Финансовую подушку даже в кризисы.


4️⃣ Престиж профессии.

🔹 Государственное признание: IT-специалисты получают льготные ипотеки, налоговые послабления и поддержку на государственном уровне как стратегически важная профессия.
🔹 Уважение среди других профессий: врачи, инженеры и представители других сложных специальностей открыто признают, что программирование требует уникального сочетания навыков и действительно трудозатратно.
🔹 Социальный капитал: в глазах общества IT-специалист автоматически получает статус умного и перспективного человека, что заметно даже в бытовых ситуациях.
🔹 Культурный статус: в кино, сериалах и СМИ образ программиста давно стал синонимом интеллекта и успеха, формируя особое восприятие профессии в массовом сознании.
🔹 Финансовая стабильность: даже junior-специалисты получают зарплаты выше среднего по рынку, а опытные разработчики могут выбирать среди предложений с шестизначными цифрами.
🔹 Влияние на будущее: разработчики напрямую участвуют в создании технологий, которые меняют мир, от медицинских решений до космических программ.


5️⃣ Постоянный вызов и рост.

🔹 Новые технологии каждые полгода (никогда не будет скучно).
🔹 Возможность решать задачи, которые еще вчера казались невозможными.
🔹 Ощущение прогресса, когда оглядываешься на свой код годовой давности.


6️⃣ Сообщество единомышленников.

🔹 IT-тусовки и митапы, где все говорят на одном языке.
🔹 Возможность находить работу через знакомых.
🔹 Общий мемный культурный код.


Мы получаем деньги за то, что решаем интересные головоломки — это же мечта любого ребенка!


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2283🔥2🤔2🤝11
Как разработчику не застрять в поиске работы на месяцы

Часто вижу, как сильные специалисты месяцами ищут работу без оффера.
Обычно дело не в рынке, а в резюме, LinkedIn и стратегии поиска.

У моего коллеги, карьерного консультанта, на канале как раз об этом:
— как переписать резюме так, чтобы оно приносило интервью
— как оживить LinkedIn и GitHub
— как строить стратегию поиска, а не хаотично откликаться

Если вы в поиске или хотите подготовиться к нему заранее, рекомендую заглянуть.
👉 https://t.me/bezpanikiIT
6👍2😁2👀21
This media is not supported in your browser
VIEW IN TELEGRAM
В Xcode 26 есть возможность попросить ИИ быстро внести изменения в код!

Пока работает только на macOS Tahoe Beta, но выглядит многообещающе.

➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
23🔥64👍11
🔢 Оператор ~= в Swift: скрытый помощник pattern matching'а.

Вы когда-нибудь задумывались, как на самом деле работает 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🔥12431
👨‍💻 Как отличить хороший код от говнокода: руководство для выживания.

Знакомо чувство, когда проект превращается в кошмар из багов и бесконечных правок? Говнокод — это не просто шутка, а реальная проблема, которая рушит продукты и команды. Вот как распознать и избежать его.


Признаки плохого кода:

🔸 Не решает задачу: код может работать без ошибок, но быть бесполезным для бизнеса.
🔸 Код пожирает ресурсы: неэффективность, из-за которой растут затраты на инфраструктуру.
🔸 Непонятная структура: даже автор кода через месяц не разберётся, что он делает и как он работает.
🔸 Копипаст: одинаковые баги в 10 местах, которые нельзя исправить одним правкой.
🔸 Глобальные переменные: скрытые зависимости, которые ломают тесты и логику.
🔸 Отсутствие тестов: изменения становятся лотереей, а релизы — русской рулеткой.


Признаки хорошего кода:

🔹 Читаемость: другой разработчик понимает его с первого взгляда.
🔹 Гибкость: легко добавлять функционал и удалять устаревшие части.
🔹 Минимальные зависимости: изменения в одном модуле не ломают всю систему.
🔹 Тесты: юнит-тесты автоматически проверяют, не сломали ли вы уже работающую функциональность.
🔹 Осмысленные имена: переменные и методы называются так, чтобы не требовались комментарии.


⚠️ Как не скатиться в хаос:

🔹 Код-ревью: обязательная проверка кода перед влитием в основную ветку.
🔹 Стандарты разработки: единый стиль для всей команды (длина строк, переносы скобок, форматирование, нейминг).
🔹 Своевременный рефакторинг: постепенное улучшение вместо переписывания с нуля.
🔹 Тесты для багов: пишем тест перед исправлением, чтобы баг не вернулся.


💡 Вывод:

Хороший код — это не про гениальность, а про дисциплину. Даже под жёсткими дедлайнами можно писать поддерживаемый код, если следовать простым правилам.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
23🔥12👍3🗿11
🔢 Task Local: Как передавать данные между задачами в Swift.

Каждая задача (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
2112👍4🔥2🙏2
🔢 Кэширование в Swift: как сделать приложение быстрее.

Кэширование — мощный инструмент, который почему-то часто упускают из виду. А ведь это идеальное решение для временного хранения данных без лишних запросов к сети или базе.


🤔 Что такое NSCache?

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
12211👍1🔥11
Технический разбор Max 😎

В канале «Prefire iOS» вышел разбор свежего APK мессенджера Max - и он развеивает многие мифы о «новом и безопасном» приложении.

Что нашли внутри:
- WebRTC для звонков
- ExoPlayer и даже TensorFlow Lite
- следы Odnoklassniki/TamTam (да, привет VK Group 👀)
- и самое главное - никакого E2EE 😬

Без сложных терминов, но с фактами, скринами и кодом.
После такого «прозрачного» взгляда на APK начинаешь совсем по-другому смотреть на работу мессенджеров.

Все подробности и ссылка на Хабр - в посте
🔥10👀5🗿4😁3👍22
👨‍💻 Новый тренд: почему сеньоры притворяются мидлами.

Оказывается, некоторые опытные разработчики сознательно скручивают свой опыт в резюме и устраиваются на несколько мидл-позиций вместо одной сеньорской. Вот главные причины этого тренда:


💵 ЗП-матч: 2 мидла > 1 сеньора.

Две мидл-зарплаты часто превышают доход сеньора, особенно если работать на западные компании. Финансовая выгода очевидна.


Схема тренда:

🔹 Притвориться мидлом на собеседовании.
🔹 Взять задачи под мидла, но делай их со скоростью сеньора.
🔹 Избегать лишних созвонов — говорить что «погружаешься в проект».
🔹 Автоматизировать рутину, использовать ИИ, оценивать задачи в 1.5-2 раза больше по срокам.


⚠️ Меньше ответственности — больше скорости.

На мидл-позициях от тебя не ждут:

🔸 Архитектурных решений.
🔸 Участия в бесконечных созвонах.
🔸 Менторства.
🔸 Высокой ответственности за продукт.

Можно просто брать таски и закрывать их в 2 раза быстрее благодаря реальному опыту.


Подводные камни:

🔸 Придется работать по 10-12 часов в день.
🔸 Риск пересекающихся митингов.
🔸 Постоянное напряжение от двойной игры.
🔸 Возможность выгорания.


💡 Вывод:

Схема работы «сеньор под прикрытием» может принести краткосрочную финансовую выгоду, но требует постоянного стресса, многозадачности и грозит выгоранием. Это тактический ход, а не стратегия карьеры — подходит только тем, кто готов платить за двойную зарплату своим временем и ментальным здоровьем.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👀18🔥112👍2😁2🗿1
🇷🇺 🍏 Apple и власти РФ ведут переговоры о запуске RuStore в России.

Происходит историческое событие: компания 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
🔢 Погружение в диспетчеризацию методов Swift.

Если вы когда-то спорили с коллегами о том, стоит ли помечать классы final для оптимизации производительности, сохраните эту статью. Она разложит все по полочкам.


⚠️ Основные типы диспетчеризации в Swift.

Swift использует два принципиально разных подхода:
🔸 Статическая диспетчеризация: быстрая, но менее гибкая.
🔸 Динамическая диспетчеризация: медленнее, зато поддерживает полиморфизм.

Динамическая диспетчеризация может негативно влиять на производительность из-за:
🔸 Потери возможности оптимизации кода.
🔸 Увеличения вероятности кэш-промахов CPU.
🔸 Накладных расходов на поиск метода в таблицах.

Ключевой момент: если компилятор может определить адрес метода на этапе компиляции — используется статическая диспетчеризация. Иначе динамическая.


1️⃣ Статическая диспетчеризация.

Встраивание (Inlining):

Компилятор может заменить вызов функции ее телом, чтобы избежать накладных расходов.

♣️ Пример:


func square(_ x: Int) -> Int {
return x * x
}

let result = square(5)

// После оптимизации компилятор может превратить это в:
let result = 5 * 5 // 25 (вычислено на этапе компиляции!)


Прямая диспетчеризация (Direct Dispatch):

Используется для:
🔹 Структур.
🔹 Перечислений.
🔹 final классов.
🔹 static и private методов.

Почему это быстро?
Адрес метода известен заранее: CPU выполняет его за одну инструкцию.


2️⃣ Динамическая диспетчеризация.

Табличная (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



3️⃣ Message Dispatch (Obj-C Runtime).

Самая гибкая, но медленная диспетчеризация через 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🫡11
🔢 Гайд по промптингу для Apple Foundation Models.

Новые 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👍1341👀1
🤖 Vibe-coding vs Prompt-engineering: два подхода к работе с ИИ.

Опытные разработчики чаще принимают ИИ-инструменты, чем новички. Возможно, дело в уверенности: сеньоры не боятся что их заменят, а видят в ИИ помощника.


1️⃣ Vibe-coding.

Как работает:
Бросаешь задачу в ChatGPT (или другие ИИ), получаешь готовый код и слегка его правишь.

Проблема:
Нет глубокого понимания кода, ментальная модель не строится.

Когда использовать:
Только для быстрых прототипов и экспериментов.

Риски:
Код может быть неоптимальным и со скытыми багами.


2️⃣ Prompt-engineering.

Как работает:
Тщательно проектируешь запросы, задаешь контекст, формат и ограничения, получаешь точный результат.

Преимущество:
Полный контроль над процессом, понимание каждой строки кода.

Идеально для:
Рутинных задач, шаблонного кода и документации.

Аналогия:
Как менторить джуна: даешь четкие инструкции и проверяешь результат.


⚠️ Ключевое отличие:

Vibe-coding: эмоциональный подход «сгенерируй что-нибудь».
Prompt-engineering: инженерный подход «дай мне конкретное решение под мои требования».


Как использовать ИИ эффективно:

🔹 Всегда включать голову: не важно откуда код: из ИИ, Stack Overflow или из статьи.
🔹 Дробить задачи: давать ИИ конкретные мелкие задания вместо «сделай все».
🔹 Тестировать и проверять: любой сгенерированный код требует ревью и тестов.
🔹 Учиться формулировать: прокачивать навык написания четких промтов.


💡 Вывод:

ИИ не замена разработчику, а мощный инструмент. Как молоток: можно собрать мебель, а можно разбить палец. Все зависит от того, кто и как его использует.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍221512🔥3🤔1🙏1
👨‍💻 IT-кризис: почему айтишники стали одними из самых безработных.

Шокирующая статистика из США: каждый 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🤯52🤔1🙏1🗿1