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

Всем привет! Сегодня поговорим о, казалось бы, базовой теме: выборе между let и var в структурах Swift. Но, как оказалось, даже здесь есть много тонкостей, которые влияют на поведение нашего кода.

Все мы знаем, что let создает константу, а var переменную. Но в контексте структур есть важные нюансы:


Проблемы с let и опциональными типами.

Когда мы используем let для опциональных свойств, мы обязаны явно передавать значения в инициализаторе, даже если хотим передать nil:


struct User {
let id: UUID
let name: String
let email: String?
}

// Ошибка компиляции: Missing argument for parameter 'email' in call
let user1 = User(
id: UUID(),
name: "Андрей"
)

// Обязаны явно указать nil для свойства email.
let user2 = User(
id: UUID(),
name: "Вася",
email: nil
)


Теперь посмотрим на пример с var:


struct User {
let id: UUID
let name: String
var email: String?
}

// Оба варианта работают:
let user1 = User(
id: UUID(),
name: "Петр"
)

let user2 = User(
id: UUID(),
name: "Иван",
email: nil
)


Использование let для опциональных свойств создает неожиданные сложности при создании экземпляров структур. Компилятор требует явно передавать значения для всех let-свойств в автоматическом инициализаторе, даже если мы хотим установить nil. Это приводит к громоздкому коду, где приходится постоянно указывать nil для необязательных полей. С var такой проблемы нет, опциональные свойства автоматически получают значение nil, если их не указать явно.


Дефолтные значения и let.

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


// id не будет задаваться в инициализаторе, он всегда будет новым (даже при декодировании из JSON):
struct User {
let id = UUID()
let name: String
}

let user = User(name: "Максим")


Когда свойство объявлено как let с дефолтным значением, оно всегда будет использовать это значение, даже при декодировании из внешних данных. Это означает, что JSON с другим значением для этого поля будет проигнорирован, что часто является ошибкой.


Кастомные инициализаторы в помощь.

Если нужна читаемост и гибкость, то напишем свой инициализатор:


struct User {
let id: UUID
let name: String
let email: String?

init(
id: UUID = UUID(),
name: String,
email: String? = nil
) {
self.id = id
self.name = name
self.email = email
}
}


Создание собственного инициализатора позволяет обойти ограничения автоматического. Мы можем определить параметры с дефолтными значениями, сохраняя при этом иммутабельность через let. Такой подход дает контроль над процессом инициализации, но требует написания дополнительного кода и его поддержки.


Property Wrapper для иммутабельности.

Можно создать кастомное решение для read-only свойств с дефолтными значениями:


@propertyWrapper
struct Readonly<Value> {
let wrappedValue: Value
}

struct User {
@Readonly var id = UUID()
var name: String
@Readonly var email: String?
}


Обертка свойства @Readonly имитирует поведение let, но с поддержкой дефолтных значений. Однако этот подход добавляет сложности и может сделать код менее читаемым.


💡 Вывод:

Начинайте с let для всех свойств, это обеспечивает безопасность и предсказуемость. Переходите на var только когда появляется реальная необходимость изменять данные.

Для опциональных свойств, где let создает неудобства, можно использовать кастомные инициализаторы с параметрами по умолчанию - это сохраняет иммутабельность без потери удобства. Идентификаторы и другие гарантированно неизменяемые данные всегда должны объявляться через let.

➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
11913👍13🙏4🔥2👏1👀1
🔢 Как правильно делать задержку в iOS приложении и не блокировать интерфейс.

Привет, друзья! Сегодня разберем как правильно организовать задержку выполнения кода в iOS-приложении.


DispatchQueue.main.asyncAfter.

Решение для задержки 2 секунды на главном потоке:


func showHelloMessage() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Привет!")
}
// Код продолжает выполняться здесь без задержек
}



Task + await.

Для асинхронного контекста:


func showHelloMessage() async {
try? await Task.sleep(for: .seconds(2))
print("Привет!")
}



Timer.

Если нужно повторять действие с интервалом:


func showHelloMessage() {
Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { _ in
print("Привет!")
}
}



Как делать не нужно.

Выполняем действие через 2 секунды:


func showHelloMessage() {
Thread.sleep(forTimeInterval: 2.0)
print("Привет!")
}


Кажется, что все работает, но за этой простотой скрывается серьезные проблемы:

🔹 Полностью блокирует поток. Пока поток «спит», он не может выполнять другие задачи, которые вы можете ожидать.
🔹 Особенно опасен на главном потоке. Если вызвать Thread.sleep() на главном потоке, ваш интерфейс зависнет на эти 2 секунды. Пользователь не сможет прокручивать скролл, нажимать кнопки, приложение будет непригодным для использования в течении этого времени.


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
23👍149🔥3🫡2🤝1
🔢 EventKit: как получить доступ к календарю пользователя в iOS.

Привет, друзья! Сегодня разберем важную тему: как правильно работать с календарем пользователя в iOS-приложениях. Многие проекты требуют доступа к событиям и напоминаниям, но не все знают тонкости реализации.


Безопасность прежде всего.

Доступ к календарю - это приватные данные пользователя. Apple строго контролирует такие запросы, поэтому первым делом настраиваем ключи в Info.plist:

<key>NSCalendarsFullAccessUsageDescription</key>
<string>Мы хотим добавить событие в ваш календарь</string>
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
<string>Приложение будет создавать события, но не читать существующие</string>



Практический пример запроса доступа.

Вот так реализуется запрос прав на доступ к событиям:

import EventKit

class CalendarManager: ObservableObject {
private let eventStore = EKEventStore()
@Published var accessStatus: EKAuthorizationStatus = .notDetermined

func requestAccess() async throws -> Bool {
let granted = try await eventStore.requestFullAccessToEvents()
await MainActor.run {
accessStatus = EKEventStore.authorizationStatus(for: .event)
}
return granted
}
}


Важные нюансы:

🔹 Write-only доступ: идеален для приложений, которые только добавляют события (билеты, бронирования).
🔹 Full access: нужен там, где требуется чтение и анализ расписания.
🔹 Статус авторизации всегда проверяйте перед операциями:

func canAddEvents() -> Bool {
let status = EKEventStore.authorizationStatus(for: .event)
return status == .authorized || status == .writeOnly
}



Использование календаря.

После успешного получения прав можно работать с событиями. Вот базовые операции:

import EventKit

class CalendarManager {
private let eventStore = EKEventStore()

// Проверяем доступ и добавляем событие
func addQuickEvent(title: String) -> Bool {
guard EKEventStore.authorizationStatus(for: .event) == .authorized else {
print("Нет доступа к календарю")
return false
}

let event = EKEvent(eventStore: eventStore)
event.title = title
event.startDate = Date() // начинается сейчас
event.endDate = Date().addingTimeInterval(3600) // длится 1 час
event.calendar = eventStore.defaultCalendarForNewEvents

do {
try eventStore.save(event, span: .thisEvent)
print("Событие '\(title)' добавлено")
return true
} catch {
print("Ошибка: \(error.localizedDescription)")
return false
}
}

// Показываем все события на сегодня
func showTodaysEvents() {
guard EKEventStore.authorizationStatus(for: .event) == .authorized else { return }

let startDate = Date()
let endDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate)!

let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
let events = eventStore.events(matching: predicate)

print("События на сегодня:")
for event in events {
print("• \(event.title ?? "Без названия") - \(event.startDate)")
}
}
}

// Использование
let calendarManager = CalendarManager()

// Добавляем событие
calendarManager.addQuickEvent(title: "Встреча с командой")

// Показываем события
calendarManager.showTodaysEvents()



Рекомендации по использованию.

🔹 Запрашивать доступ в контексте (когда пользователь пытается создать первое событие).
🔹 Предварительно проверять статус и показывать соответствующий UI.
🔹 Всегда обрабатывать сценарий отказа.
🔹 Тестируйте на реальном устройстве, симулятор может не полностью эмулировать права доступа.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
20👍148🤝4🤯1
Forwarded from Кот Денисова
👨‍💻 Рынок IT изменился навсегда. Как не остаться за бортом.

Коллеги, давайте честно: если вы разработчик и не можете найти работу, скорее всего это не ваша вина. Рынок изменился, но он не «умер». Он просто стал другим, более жестким, более избирательным и требующим новых стратегий. И сейчас я объясню, почему это даже хорошо для тех, кто готов адаптироваться.

Раньше IT воспринималось как социальный лифт: прошел курсы -> получил зарплату в 2-3 раза выше средней. Сейчас медианная зарплата разработчика в России около 200 тысяч рублей. Это достойные деньги, но уже не запредельные. Курьеры в крупных городах зарабатывают сопоставимо, а иногда и больше. IT перестало быть гарантией быстрого обогащения, но осталось сферой, где можно строить осмысленную и интересную карьеру.


Почему рынок изменился:

🔹 Перенасыщение. После бума 2010-х годов на рынок хлынули тысячи новичков. Сегодня на одну вакансию мобильного разработчика могут претендовать сотни кандидатов. Рекрутеры вынуждены устраивать «заградительные собеседования», чтобы отсеять тех, кто не соответствует требованиям.

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

🔹 Санкции и уход западных компаний. Закрытие Apple App Store для российских разработчиков, ограничения Google Play, все это сократило количество рабочих мест и заставило многих iOS-разработчиков переквалифицироваться.

🔹 Рост no-code решений. Такие технологии, как BDUI (Backend-Driven UI), позволяют быстро создавать и обновлять интерфейсы без глубоких знаний нативной разработки. Бизнес все чаще выбирает экономию времени и ресурсов.

🔹 ИИ как конкурент. GPT и другие модели уже сегодня генерируют код на уровне джуниоров. Скоро контекстное окно увеличится до миллиарда токенов, и ИИ сможет самостоятельно создавать сложные приложения, интегрируясь с внешними API. Это изменит роль разработчика с «пишущего код» на «архитектора и контролера».

Но это не конец. Это новая реальность, в которой выживут сильнейшие, те, кто готов учиться, адаптироваться и предлагать уникальную ценность.


Что делать:

🔹 Сменить фокус с технологий на архитектуру. Умение проектировать системы, а не просто писать код, станет ключевым навыком. Изучайте чистую архитектуру, SOLID, паттерны проектирования. Ваша цель стать не «разработчиком», а «архитектором, который решает бизнес-задачи».

🔹 Освоить смежные области. Fullstack, DevOps, безопасность - все, что делает вас универсальным специалистом. Например, умение работать с облачной инфраструктурой (Kubernetes, Docker) или понимание принципов кибербезопасности резко повысит вашу ценность.

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

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

🔹 Рассмотреть смежные профессии. Data Engineering, ИИ-разработка - это направления, где спрос будет только расти. Да, придется учиться с нуля, но это инвестиция в будущее.


💡 Вывод:

Да, рынок разработки больше не будет прежним. Но это не трагедия, а возможность перезагрузки. Те, кто готов меняться, углублять знания и брать на себя больше ответственности, не просто выживут, они окажутся в выигрыше. Ваша карьера зависит не от внешних обстоятельств, а от готовности расти вместе с технологиями.


🔗 Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
18👍13🔥8🙏4🤔11
🔢 Swift Collections: Секретное оружие для эффективного кода.

Часто в повседневной работе нам кажется, что массивы, словари и множества покрывают все задачи, но есть инструменты, которые могут сделать ваш код эффективнее, чище и надежнее. Сегодня разберем несколько структур из библиотеки swift-collections, которые решат проблемы, о которых вы могли не подозревать.


Deque.

Deque - это оптимизированная версия массива, которая позволяет добавлять и удалять элементы с начала и конца за O(1). В то время как Array тратит O(n) на вставку в начало.

Пример:

Например, код из фоторедактора с функцией отмены последних действий.


import Collections

final class ActionHistory<Action> {
private var history: Deque<Action> = []
private let capacity: Int

init(capacity: Int = 50) {
self.capacity = capacity
}

func addAction(_ action: Action) {
if history.count >= capacity {
history.removeFirst() // Удаляем самое старое действие
}
history.append(action)
}

func undo() -> Action? {
history.popLast()
}
}


При частом изменении начала коллекции Deque работает значительно быстрее Array.


Heap.

Heap автоматически сортирует элементы по приоритету. Например, идеально для обработки задач с разной срочностью.

Пример:

Система уведомлений, где сообщения от администратора должны показываться первыми.


struct Notification: Comparable {
let message: String
let priority: Int

static func < (lhs: Notification, rhs: Notification) -> Bool {
lhs.priority < rhs.priority
}
}

var notifications = Heap<Notification>()
notifications.insert(Notification(message: "Обновление системы", priority: 1))
notifications.insert(Notification(message: "Новое сообщение", priority: 3))

// Сначала получим уведомление с priority = 3
let nextNotification = notifications.popMax()



OrderedSet.

OrderedSet - это гибрид Array и Set, который сохраняет порядок элементов и гарантирует их уникальность.

Пример:

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


var recentProducts = OrderedSet<String>()
recentProducts.append("iPhone 17")
recentProducts.append("iPad Pro")
recentProducts.append("iPhone 17") // Не добавится

print(recentProducts) // ["iPhone 17", "iPad Pro"]



OrderedDictionary.

OrderedDictionary - это словарь, который запоминает порядок добавления элементов.

Пример:

Кэширование данных для экрана списка, где порядок элементов важен.


var userCache = OrderedDictionary<String, User>()
userCache["user_1"] = User(name: "Анна")
userCache["user_2"] = User(name: "Иван")

// Порядок сохраняется при обходе
for (id, user) in userCache {
print("\(id): \(user.name)") // user_1: Анна, user_2: Иван
}



Зачем это все нужно:

🔹 Производительность: правильные структуры данных экономят ресурсы.
🔹 Читаемость: код становится проще для понимания.
🔹 Надежность: меньше шансов допустить ошибку в реализации.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2315🙏8🔥221
🔢 Swift Configuration: новая библиотека для работы с настройками от Apple.

Друзья, привет! Apple выпустила долгожданную библиотеку Swift Configuration - универсальное решение для управления настройками в Swift-проектах. Расскажу, чем она полезна и как начать ее использовать.


Что такое Swift Configuration:

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


Основные возможности:

🔹 Единый API: одинаковый код для всех источников настроек.
🔹 Горячее обновление: изменения применяются без перезапуска приложения.
🔹 Поддержка вложенности: работа со сложными структурами настроек.
🔹 Приоритеты источников: четкая иерархия важности настроек.


Пример:


import Configuration

// Настройка чтения из разных источников
let config = ConfigReader(providers: [
EnvironmentVariablesProvider(), // Переменные окружения
CommandLineArgumentsProvider(), // Аргументы командной строки
try await JSONProvider(filePath: "/app/config.json") // JSON-файл
])

// Чтение значения (ищет в порядке приоритета)
let timeout = config.int(forKey: "http.timeout", default: 30)
let host = config.string(forKey: "database.host", default: "localhost")



Как это работает в реальном проекте:

Представьте, у вас есть базовые настройки в JSON:


{
"database": {
"host": "localhost",
"port": 5432
}
}


Но для production вы можете переопределить их через переменные окружения:


export DATABASE_HOST=production_db.test.ru


Библиотека автоматически выберет значение из переменной окружения как более приоритетное.


Преимущества:

🔹 Снижение количества шаблонного кода: больше не нужно писать парсеры для каждого типа конфигов.
🔹 Упрощение тестирования: легко подменять настройки в тестах.
🔹 Гибкость развертывания: разные среды через разные источники настроек.


🔗 Ссылка на подробную статью


💡 Вывод:

Swift Configuration - это серьезный шаг к стандартизации работы с настройками в Swift-экосистеме. Библиотека пока сыровата для продакшена, но идеи стоят внимания. Особенно ценна унификация доступа к разным источникам конфигов.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
18🔥12👍611
📱 Тестируем пуш-уведомления на iOS-симуляторе.

Здравствуйте, друзья! Сегодня мы разберем как тестировать пуш-уведомления на симуляторе без заморочек с сервером и реальными устройствами. Это особенно актуально когда нужно быстро проверить внешний вид или логику обработки уведомлений.


Подготовка: запрашиваем разрешения.

Первым делом нужно запросить разрешение на показ уведомлений. Без этого даже идеально настроенный пуш не сработает:


import UserNotifications

UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .sound, .badge]
) { granted, error in
print("Разрешение получено: \(granted)")
}



Два способа отправки пушей.


Способ 1: Drag & Drop (самый простой)

Создаем JSON-файл notification.apns с содержимым уведомления:


{
"aps": {
"alert": {
"title": "Новое сообщение",
"body": "Вам пришло новое сообщение в чате"
},
"badge": 1,
"sound": "default"
},
"Simulator Target Bundle": "com.yourapp.bundleid"
}


Просто перетаскиваем файл на симулятор, уведомление появится мгновенно!


Способ 2: Через терминал (для автоматизации)

Узнаем ID симулятора:


xcrun simctl list


Отправляем пуш:


xcrun simctl push booted com.yourapp.bundleid notification.apns


Ключевое слово booted автоматически определяет запущенный симулятор.


Что еще можно протестировать.

На симуляторе отлично работают:

🔹 Rich-уведомления с картинками.
🔹 Кастомные звуки.
🔹 Action-кнопки.
🔹 Deep links.
🔹 Badge-иконки.


Частые ошибки:

🔹 Не указан Simulator Target Bundle: симулятор не поймет, какому приложению предназначен пуш.
🔹 Нет разрешений: забыли вызвать requestAuthorization.
🔹 Неверный bundle identifier: проверьте точное написание в проекте.


🔗 Ссылка на подробную статью


💡 Вывод:

Тестировать пуш-уведомления на симуляторе стало проще простого. Не нужно настраивать серверную часть, достаточно JSON-файла и пары команд. Единственное ограничение - некоторые продвинутые функции вроде фоновых обновлений контента лучше проверять на реальном устройстве. Но для 90% повседневных задач симулятора более чем достаточно.

Стоит отметить, что на iOS 26 симуляторах иногда наблюдаются проблемы, при тестировании пуш-уведомлений. Если у вас возникли проблемы, попробуйте протестировать на предыдущих версиях iOS.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
2011🔥5🙏2👍11
Forwarded from Кот Денисова
This media is not supported in your browser
VIEW IN TELEGRAM
🆘 Возвращение легенды: Stack Overflow запускает свой ИИ.

Пока все обсуждают ChatGPT и Copilot, легендарный Stack Overflow тихо готовит ответный удар. И у них есть серьезное преимущество: гигантская база проверенных ответов, которые создавали мы с вами все эти годы.


Что происходит?

Stack Overflow анонсировал собственную ИИ-систему Overflow AI. И это не просто очередной чат-бот, а интеграция их огромной базы знаний в рабочие процессы разработчиков.


Ключевые фишки:

🔹 Умный поиск: можно задавать вопросы естественным языком.
🔹 Интеграция с VS Code: помощь прямо в редакторе кода.
🔹 Slack-бот: ответы на технические вопросы в рабочих чатах.
🔹 Корпоративная версия: поиск по внутренним базам знаний компаний.


Мое мнение:

Stack Overflow может стать антидотом от ИИ-багов. Особенно ценна корпоративная версия, представьте, ИИ ищет ответы не только в публичной базе, но и в вашем внутреннем Confluence, GitHub и документации.


💡 Вывод:

Игра только начинается. Stack Overflow может занять нишу правильного ИИ для разработчиков, где важна точность, а не креативность.


🔗 Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
21🔥14👍9👏3👀11
🔢🏋️ Swift на Android: один код для двух платформ.

Друзья, привет! Случилось то, о чем многие давно мечтали, но мало кто верил это произойдет! После месяцев работы рабочей группы по поддержке Android, компания Apple выпустила первую версию Swift SDK для разработки под операционную систему Android.


Масштабы поддержки:

Уже сейчас 25% пакетов в Swift Package Index поддерживают сборку для Android. Среди них многие популярные библиотеки, которые мы используем в повседневной разработке.

Стоит отметить, что код компилируется на Java и Kotlin, так как Android пока еще нативно не поддерживает Swift.


Что нужно для старта:

🔹 Установите Swift 6.3: раннюю версию с поддержкой Android.
🔹 Загрузите Swift SDK для Android: отдельно или в составе установщика для Windows.
🔹 Добавьте Android NDK: для нативной компиляции.

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


Почему это важно:

🔹 Больше не нужно учить Kotlin/Java для разработки под Android, если вы владеете Swift.
🔹 Единая бизнес-логика, кодовая база и архитектурные подходы на обеих платформах.
🔹 Снижение затрат, одна команда вместо двух раздельных под каждую из платформ.


Перспективы:

Рабочая группа уже готовит дорожную карту развития платформы. В планах: улучшение отладки, оптимизация производительности и расширение поддержки Android API.


Что важно понимать:

🔹 Это предварительная версия, некоторые функции ещё в разработке.
🔹 Требуется время на стабилизацию и полировку.
🔹 Не все iOS-библиотеки сразу будут работать на Android.


💡 Вывод:

Swift на Android - это не просто ещё одна кроссплатформенная технология, это возможность создать по-настоящему единую кодовую базу с нативной производительностью на языке программирования Swift.

Это может изменить расстановку сил на рынке мобильной разработки. KMM, Flutter и React Native получают мощного конкурента, а нативные разработчики новые возможности.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2515👍9🤔221
🔢 Observations: современный подход к отслеживанию изменений данных в Swift.

С выходом Swift 6.2 появился новый мощный инструмент для наблюдения за изменениями в @Observable моделях. Сейчас расскажу, как это работает и чем отличается от предыдущих подходов.


Что изменилось:

Раньше мы использовали withObservationTracking с его неудобным API и семантикой will set. Теперь появился объект Observations, который создает AsyncSequence для отслеживания изменений свойств.


Пример:

Допустим, у нас есть модель счетчика:


@Observable
class Counter {
var count = 0
var name = "Счетчик"
}


Старый подход:


class CounterObserver {
func observeOldWay(counter: Counter) {
withObservationTracking {
print("Текущее значение: \(counter.count)")
} onChange: {
self.observeOldWay(counter: counter) // Рекурсивный вызов
}
}
}


Новый подход:


class CounterObserver {
func observeNewWay(counter: Counter) {
Task { [weak self] in
let values = Observations { [weak self] in
guard let self else { return "" }
// Наблюдаем за count и name, но возвращаем форматированную строку
return "\(self.counter.name): \(self.counter.count)"
}

for await value in values {
print("Обновление: \(value)")
// Обновляем UI или выполняем другую логику
}
}
}
}


Еще один пример:


class UserProfileManager {
@Observable class UserProfile {
var username: String
var email: String
var isOnline: Bool
}

func startObservingProfile() {
Task { [weak self] in
let profileUpdates = Observations { [weak self] in
guard let self else { return false }
// Наблюдаем за несколькими свойствами
let status = self.userProfile.isOnline
let name = self.userProfile.username
return (status, name)
}

for await (isOnline, username) in profileUpdates {
await self?.updateUserInterface(isOnline: isOnline, username: username)
}
}
}
}



Преимущества нового подхода:

🔹 Более чистый код: никакой рекурсии.
🔹 AsyncSequence: интегрируется с современным асинхронным Swift.
🔹 Гибкость: можно возвращать любой тип данных.
🔹 Автоматическое отслеживание: наблюдаются все свойства, доступные в closure.


🔗 Ссылка на подробную статью


💡 Вывод:

Observations существенно упрощает отслеживание изменений данных по сравнению с предыдущими подходами. Теперь не нужно писать рекурсивные вызовы, достаточно создать асинхронную последовательность и обрабатывать обновления в цикле.

➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19159🔥2👀2🙏11
🔢 iOS 26.1: новый протокол для фоновой выгрузки ресурсов.

В iOS 26.1 компания Apple представила новый тип расширений для PhotoKit: Background Resource Upload. Это обновление, которое перекладывает управление фоновыми загрузками на саму операционную систему.


Что это такое?

PHBackgroundResourceUploadExtension - это новый протокол, который позволяет системе управлять загрузкой ресурсов от имени вашего приложения. Теперь iOS сама обрабатывает загрузки, даже когда пользователь переключился на другое приложение или заблокировал устройство.


Как это работает.

Система предоставляет два основных метода:


// Запрос на обработку фоновых загрузок
func process() -> PHBackgroundResourceUploadProcessingResult

// Уведомление о завершении работы
func notifyTermination()



Ключевые компоненты API:

🔹 PHBackgroundResourceUploadExtension: основной протокол для расширений фоновой загрузки.
🔹 PHBackgroundResourceUploadProcessingResult: enum с результатами обработки.
🔹 PHAssetResourceUploadJob: представляет запрос на загрузку ресурса PHAsset.
🔹 PHAssetResourceUploadJobChangeRequest: для управления записями загрузок.


Преимущества подхода:

🔹 Автоматическое управление сетью: система сама оптимизирует подключения.
🔹 Энергоэффективность: загрузки в оптимальное время для батареи.
🔹 Надежность: обработка даже при блокировке устройства.
🔹 Умные тайминги: система выбирает лучшее время для загрузок.


Для каких задач подходит.

Идеально для приложений, которые:

🔹 Выполняют бэкап фотографий в облако.
🔹 Синхронизируют медиаресурсы с серверами.
🔹 Загружают тяжелые видеофайлы.
🔹 Работают с большими коллекциями изображений.


Важные нюансы:

🔹 Пока доступно только в PhotoKit.
🔹 API находится в бета-версии.
🔹 Требуется iOS 26.1+
🔹 Документация может измениться.


🔗 Документация на сайте Apple


💡 Вывод:

Новый API Background Resource Upload - это серьезное упрощение для разработчиков, работающих с медиаресурсами. Система берет на себя всю сложность управления фоновыми задачами, позволяя сосредоточиться на бизнес-логике приложения.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
18👍14🔥73👀11
🔢 Тестируем приватные свойства без нарушения инкапсуляции в Swift.

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


Проблема, знакомая каждому.

Представьте ситуацию: у вас есть класс с приватным кэшем:


class PaymentProcessor {
private var cache: [String: Payment] = [:]

func processPayment(_ payment: Payment) {
// Сложная логика с использованием cache
}
}


Как протестировать, что кэш действительно работает? Раньше были только два неидеальных варианта:

🔹 Сделать cache internal: нарушаем инкапсуляцию.
🔹 Тестировать только через публичные методы: тесты становятся сложными и хрупкими.


Решение.

Swift предлагает атрибут @_private(sourceFile:), который позволяет получить доступ к приватным членам в тестах:


#if ENABLE_PRIVATE_TESTS
@_private(sourceFile: "PaymentProcessor.swift")
import MyApp
#endif

func testCacheBehavior() {
let processor = PaymentProcessor()

// Теперь можем напрямую работать с приватным cache!
XCTAssertTrue(processor.cache.isEmpty)
}



Настройка.

🔹 Шаг 1: Включаем приватные импорты в основном модуле. В Package.swift:


.target(
name: "MyApp",
swiftSettings: [
.unsafeFlags(["-Xfrontend", "-enable-private-imports"])
]
)


🔹 Шаг 2: Условная компиляция в тестах:


#if ENABLE_PRIVATE_TESTS
@_private(sourceFile: "PaymentProcessor.swift")
import MyApp
#endif


🔹 Шаг 3: Настраиваем переменную окружения. В схеме тестирования:


ENABLE_PRIVATE_TESTS=1



🔗 Ссылка на подробную статью


💡 Вывод:

@_private(sourceFile:) - инструмент для серьезных проектов, где важны качественные тесты. Используйте его осознанно, всегда оборачивайте в флаги компиляции и будьте готовы к тому, что в будущих версиях Swift он может перестать работать.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥13🤔6👀521🙏1🗿1
🔢 Новая навигация в UIKit 26: теперь с подзаголовком и гибким поиском.

Друзья, Apple продолжает сближать UIKit и SwiftUI! В iOS 26 обе технологии получают мощные обновления навигации, которые избавят нас от кастомных решений и костылей.


Что нового в UIKit.

Подзаголовки в UINavigationItem:


// Базовый подзаголовок
let navItem = navigationItem
navItem.title = "Профиль"
navItem.subtitle = "Премиум аккаунт"

// Стилизованная версия
let attributedSubtitle = AttributedString(
"Активен до 25.12.2026",
attributes: AttributeContainer([
.foregroundColor: UIColor.systemGreen,
.font: UIFont.systemFont(ofSize: 12, weight: .medium)
])
)
navItem.attributedSubtitle = attributedSubtitle


Гибкий поиск с новыми вариантами размещения:


// Разные варианты поиска
searchController.searchBarPlacement = .integrated // Встроенный
searchController.searchBarPlacement = .integratedButton // Как кнопка
searchController.searchBarPlacement = .integratedCentered // Центрированный



Что нового в SwiftUI.

Подзаголовки в NavigationStack:


struct ProfileView: View {
var body: some View {
NavigationStack {
Text("Контент профиля")
.navigationTitle("Профиль")
.navigationSubtitle("Премиум аккаунт") // Новое в iOS 26!
}
}
}


Liquid Glass для навигации:


.navigationBarTitleDisplayMode(.large)
.background(.ultraThinMaterial) // Эффект стекла



💡 Вывод:

iOS 26 делает навигацию единой для UIKit и SwiftUI. Больше не нужно выбирать между технологиями, можно создавать современные интерфейсы используя нативные API обеих платформ.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
19👍15🔥9621
🔢 Оптимальное создание миниатюр с помощью CGImageSource.

Создание миниатюр - одна из самых распространенных задач в мобильной разработке. Но не все методы одинаково эффективны. Рассмотрим, как разные подходы показывают себя на практике при работе с 12-мегапиксельным JPEG.

Классические методы показывают разную производительность:

🔹 NSImage на macOS: 710 мс.
🔹 UIGraphicsImageRenderer на iOS: 210 мс.
🔹 UIImage.prepareThumbnail() на iOS: 130 мс.

Специализированные методы демонстрируют лучшие результаты:

🔹 CGImageSource на macOS: 16-26 мс.
🔹 CGImageSource на iOS: 24-95 мс в зависимости от формата.


Пример использования CGImageSource:


let source = CGImageSourceCreateWithData(imageData as CFData, nil)!

let cgThumb = CGImageSourceCreateThumbnailAtIndex(source, 0, [
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height)
] as CFDictionary)!

let thumbnail = UIImage(cgImage: cgThumb) // или NSImage в macOS



Ключевые параметры:

🔹 kCGImageSourceCreateThumbnailFromImageAlways: гарантирует создание миниатюры.
🔹 kCGImageSourceCreateThumbnailWithTransform: учитывает ориентацию изображения.
🔹 kCGImageSourceThumbnailMaxPixelSize: задает максимальный размер.


Получение информации о размерах:


let source = CGImageSourceCreateWithData(data as CFData, nil)!
if let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any],
let width = properties[kCGImagePropertyPixelWidth] as? Int,
let height = properties[kCGImagePropertyPixelHeight] as? Int {
print("Ширина: \(width), высота: \(height)")
}



Преимущества CGImageSource:

🔹 Мгновенное получение размеров изображения (2-4 мс).
🔹 Работа с различными форматами (HEIC, JPEG, PNG).
🔹 Эффективное использование памяти.
🔹 Поддержка последовательной загрузки.


🔗 Ссылка на подробную статью


💡 Вывод:

CGImageSource показывает стабильно высокую производительность на обеих платформах, особенно заметно ускорение на macOS: до 40 раз по сравнению с классическими методами. Для задач, связанных с отображением галерей или списков изображений, этот подход становится оптимальным выбором.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
18👍14🔥106🤝3👀21
Forwarded from Кот Денисова
👨‍💻 Реалии разработки: почему 50% времени уходит не на код.

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


Цикл разработки, который знаком каждому:


Неделя 1: начало разработки.

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


Неделя 2: ожидания тестирования.

Отдел тестирования перегружен, ваша задача висит в статусе «готова к тестированию». Вы переключаетесь на другие задачи и проекты, постепенно забывая детали реализации. Контекст стирается, а энтузиазм угасает.


Неделя 3: неожиданное возвращение.

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


Немного статистики:

🔹 Каждая третья фича возвращается на доработку минимум один раз.
🔹 15% задач требуют кардинальных изменений после тестирования.
🔹 Среднее время ожидания тестирования: от 2 дней до 7 дней.
🔹 Большинство разработчиков одновременно ведут несколько задач.


Почему так происходит:

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


Как с этим работать:


Ментальные практики:

🔹 Не привязываться эмоционально к написанному коду.
🔹 Воспринимать изменения не как неудачу, а как возможность сделать продукт лучше.
🔹 Понимать, что выпиливание фичи - это не личное поражение, а забота о пользователе.


Построить рабочие процессы:

🔹 Организовать регулярные встречи с продукт-менеджерами для синхронизации.
🔹 Проводить промежуточные демо для стейкхолдеров до финального тестирования.
🔹 Выполнить детальные чек-листы перед сдачей задачи.
🔹 Назначить четкие критерии приемки для каждой фичи.


💡 Вывод:

Процесс разработки - это живой организм, который постоянно меняется. Умение адаптироваться, сохранять гибкость и не терять энтузиазм в цикле бесконечных доработок - вот что отличает профессионала.


🔗 Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1914🙏10👀6🤝21
🔨 Важные изменения в Xcode 26.1 beta.

Привет, друзья! Сегодня поговорим о нововведения в Xcode 26.1 beta, которые повлияют на нашу повседневную работу:


SPM стал чуть умнее.

Локальное кэширование пакетов из реестра на час - это мелкое, но важное улучшение. Представьте: у вас в команде 10 человек, и все одновременно запускают pod install после обновления версии зависимости. Раньше каждый качал одно и то же, нагружая сеть. Теперь первый, кто скачал, становится локальным «источником» на час. Мелочь, а приятно, особенно для больших команд.


Instruments снова в строю.

На новых устройствах отказывал работать Processor Trace. Теперь это починили. Для тех, кто занимается глубокой оптимизацией и профилированием, это огромное облегчение. Теперь не нужно держать под рукой старый девайс, чтобы найти узкое место в производительности.


Coding Assistant перестал жрать память.

У кого были проекты с гигантскими git-репозиториями (например, с кучей субмодулей), тот знает, как Coding Assistant мог превратить MacBook в печку. Улучшение потребления памяти - это не про «удобства», это про возможность вообще работать с этим инструментом на реальных проектах.


Симулятор перестал чудить с JSON.

Команда simctl list devices --json снова работает корректно. Казалось бы, ерунда. Но это большая ерунда для всех, кто завязал на нее свои CI/CD-скрипты для автоматического тестирования на разных типах девайсов. Скрипты снова стали предсказуемыми.


Известные проблемы: будьте осторожны!

А вот здесь классика жанра. Apple выпускает бету, но перекладывает часть проблем на нас.

🔹 Симуляторы не запускаются. Первая сборка может упереться в то, что симулятор не загрузится.
Решение: Apple рекомендует вручную выполнить в терминале:


xcrun simctl runtime dyld_shared_cache update --all


🔹 Coding Assistant все еще подводит. Инструмент поиска по файлу может возвращать неверные номера строк. Представьте: вы хотите заменить все вхождения oldVariable на newVariable, а он из-за сбитого номера строки меняет не то, что нужно, и ломает вам логику. Пока что на этот инструмент лучше не полагаться в критичных операциях.


🔗 Xcode 26.1 beta Release Notes


💡 Вывод:

Xcode 26.1 beta - это типичный «качельный» апдейт. С одной стороны, мы видим долгожданные и очень точечные фиксы старых проблем (особенно в Instruments и SPM), которые реально облегчают жизнь. С другой получаем новые сюрпризы, которые могут остановить работу.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
16🔥13👍1032😁1👀1
🔢 Как Swift 6.2 сделал работу с зависимостями приятнее.

Вместе с выходом Swift 6.2 незаметно для многих произошли важные изменения в системе управления пакетами. Те, кто уже обновился, могли заметить, что сборки стали стабильнее, а некоторые процессы быстрее. Давайте разберемся, что именно изменилось и как это повлияет на вашу повседневную работу.


Безопасность памяти теперь под контролем.

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

Полезно для:

🔹 Серверных приложений.
🔹 Финансовых проектов.
🔹 Систем с повышенными требованиями к надежности.


Макросы перестали тормозить сборку.

Если вы используете макросы вроде @Observable или создаете собственные, теперь можете рассчитывать на ускорение сборки до 30%. Система научилась использовать предварительно собранные компоненты вместо постоянной перекомпиляции зависимостей.

Особенно заметно в CI/CD: в некоторых случаях экономия времени достигает нескольких минут на каждой сборке.


Умное кеширование экономит время.

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

Когда полезно:

🔹 При работе в монорепозитории.
🔹 При частых пересборках.
🔹 При одновременной разработке нескольких связанных проектов.


Гибкие настройки диагностики.

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


💡 Вывод:

Обновление принесло именно те улучшения, которых не хватало многим разработчикам. Сборки стали значительно быстрее, работа с зависимостями удобнее, а контроль качества кода гибче. Особенно заметны эти изменения в больших проектах, где каждая минута сборки буквально на счету.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1814🔥83👀21👏11
👨‍💻 Веб-версия App Store: как Apple упрощает поиск приложений.

Компания Apple запустила полноценную веб-версию App Store. Теперь можно искать и просматривать приложения со всех платформ Apple (iPhone, iPad, Mac, Apple Watch и Apple TV) прямо в браузере на любом устройстве.


Что изменилось?

Раньше ссылки на приложения вели на отдельные страницы с минимумом информации. Теперь это полнофункциональный магазин в браузере с:

🔹 Единым каталогом всех приложений.
🔹 Вкладкой Today с подборками и историями.
🔹 Разделами игр и Apple Arcade.
🔹 Полноценными страницами приложений со скриншотами, описаниями и видео.


Почему это важнее, чем кажется:

🔹 Кроссплатформенный поиск: теперь можно найти приложение, которое доступно одновременно на iPhone, iPad и Mac, и увидеть все варианты на одной странице. Больше не нужно переключаться между устройствами.

🔹 Обмен ссылками стал проще: отправляешь знакомому ссылку на полезное приложение и он может сразу посмотреть его описание и скриншоты, даже если у него под рукой только Android-телефон или ПК.

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


🔗 Ссылка на веб-версию App Store


💡 Вывод:

Этот шаг Apple не просто техническое обновление, а стратегический ход навстречу пользователям за пределами их экосистемы. Компания наконец-то признала реальность: миллионы людей используют смешанные устройства, например Windows с iPhone, и должны иметь возможность комфортно знакомиться с приложениями Apple.

Особенно важно, что веб-версия кардинально меняет процесс принятия решения о покупке. Теперь не нужно использовать iPhone или Mac, чтобы просто посмотреть, как выглядит приложение, достаточно открыть браузер на любом устройстве.

Для разработчиков это открывает новые возможности продвижения. Теперь можно эффективно работать с SEO и контент-маркетингом, направляя трафик напрямую в App Store из браузера. Пиар приложений выходит на новый уровень.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍1211😁5🤯22👏1
🔢 OptionSet: эффективная работа с флагами и настройками в Swift.

Привет! Сегодня хочу разобрать один из самых недооцененных инструментов в Swift: OptionSet. Это не просто протокол, а элегантное решение для задач, с которыми мы сталкиваемся почти в каждом проекте.


Для чего нужен OptionSet?

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

Чаще всего, когда в коде нужно описать какие-то варианты выбора, разработчики сразу вспоминают про enum. Это действительно правильный подход для ситуаций, где может быть выбран только один вариан, например при статусах заказа: «в обработке», «доставляется» или «выполнен».

Но вот в чем проблема: когда нам нужно выбрать сразу несколько вариантов одновременно (например, показать и поиск, и фильтр, и сортировку), обычное перечисление не подходит. Пришлось бы создавать отдельные варианты для всех возможных комбинаций: «поиск_и_фильтр», «поиск_и_сортировка» и так далее. Это очень неудобно и громоздко.

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


Пример.

Допустим, мы делаем тот самый список задач. Вот как может выглядеть наша конфигурация:


struct TasksListOptions: OptionSet {
let rawValue: Int

static let showFilter = TasksListOptions(rawValue: 1 << 0) // 0001
static let showSearch = TasksListOptions(rawValue: 1 << 1) // 0010
static let showSort = TasksListOptions(rawValue: 1 << 2) // 0100
static let showLayoutSelector = TasksListOptions(rawValue: 1 << 3) // 1000
}


Вся мощь OptionSet раскрывается, когда мы начинаем его использовать. Допустим, у нас есть экран «Сегодня» и экран «Все задачи». Для каждого из них мы можем легко задать нужный набор опций прямо при создании:


let todayOptions: TasksListOptions = [.showFilter, .showSearch]

let allTasksOptions: TasksListOptions = [.showFilter, .showSearch, .showSort, .showLayoutSelector]

// Для архива ничего не нужно
let archiveOptions: TasksListOptions = []


Теперь в коде это выглядит чисто и понятно. Когда мы создаем ViewModel для каждого экрана, мы просто передаем соответствующий набор опций:


let todayViewModel = TasksListViewModel(options: todayOptions)
let allTasksViewModel = TasksListViewModel(options: allTasksOptions)
let archiveViewModel = TasksListViewModel(options: archiveOptions)


Самое удобное, что мы можем легко проверять, какие опции активны в любой момент:


class TasksListViewModel {
let options: TasksListOptions

var shouldShowSearch: Bool {
return options.contains(.showSearch)
}

var shouldShowSort: Bool {
return options.contains(.showSort)
}
}


Технически, можно было бы использовать Set<Enum>, но зачем?


Приемущества OptionSet:

🔹 Производительность: работа на уровне битовых операций - это максимально быстро.
🔹 Минимальное потребление памяти: все флаги хранятся в одном числе.
🔹 Готовый API: contains, insert, remove, union и другие операции из коробки.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
19👍15105🙏2🤯1
😊 RuStore для iOS: верим, что это только начало большого успеха.

В сети обнаружили любопытную функцию в тестовой версии RuStore для Android: возможность установки приложений на iPhone. Технология получила название RuStore Bridge, но ее реализация вызвала больше вопросов, чем восторгов.


Как это работает сейчас:

🔹 Нужен Android-смартфон с модифицированной версией RuStore.
🔹 iPhone подключается к Android-устройству по проводу.
🔹 Требуется использовать «Временный Apple ID» от разработчиков RuStore.
🔹 В каталоге пока только одно приложение: Промсвязьбанк, на котором можно опробовать работу данной технологии.


Ограничения:

🔹 Нужно удалить основную версию RuStore.
🔹 Кабели USB-C на USB-C не подходят, нужен кабель USB-A с переходником.
🔹 Авторизация только по SMS (аккаунты Яндекса и VK не поддерживаются).


🔗 Источник


💡 Мое мнение:

Это важный, первый шаг, который показывает, что команда RuStore активно ищет решения для пользователей iOS. Да, текущая реализация выглядит сложной, но помните: все великие проекты начинались с прототипов.

Технология RuStore Bridge - это доказательство того, что российские разработчики не сдаются и продолжают инновации даже в сложных условиях. Тот факт, что они нашли способ обойти ограничения, уже заслуживает уважения.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍18🔥13👀8😁53🤯21
👨‍💻 App Store Connect: важные изменения для разработчиков.

Всем привет! Apple выпустила набор обновлений для App Store Connect, которые на первый взгляд кажутся минорными, но могут серьезно повлиять на наши рабочие процессы. Это не громкие анонсы, а скорее точечные улучшения, которые стоит иметь в виду.


Изменения в процессе ревью.

Теперь можно отправлять отдельные компоненты приложения на проверку, не дожидаясь завершения основного ревью. Например:

🔹 In-App Events, пока основная версия приложения еще на проверке.
🔹 Критический фикс, не связанный с текущими кастомными страницами.
🔹 Компоненты Game Center (достижения, таблицы лидеров) отдельно от основной сборки.

Это действительно упрощает жизнь, особенно когда нужно срочно пофиксить баг или запустить событие к определенной дате. Раньше такие ситуации превращались в долгое ожидание полноценной проверки.


Кастомные продуктовые страницы.

Лимит кастомных продуктовых страниц увеличен с 35 до 70. Но главное: теперь можно назначать ключевые слова для каждой страницы.

Например, если у вас приложение для редактирования фото, можно создать отдельные страницы для редактирования портретов (ключевые слова: «портрет», «ретушь»), обработки пейзажей (ключевые слова: «пейзаж», «природа»), создания коллажей (ключевые слова: «коллаж», «фоторедактор»).


Промо-коды для всех типов покупок.

Теперь промо-коды работают для всех типов In-App Purchases:

🔹 Consumable (потребляемые товары).
🔹 Non-consumable (непотребляемые покупки).
🔹 Non-renewing subscriptions (подписки без авто-продления).


🔗 Подробнее в посте Apple Developer


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥15942🙏1🤝1