DerDieDas. Каким я вижу это приложение?
Самое важное - это должно быть очень простое приложение - с минимальным функционалом и лаконичным дизайном. Никакой перегрузки интерфейса: всё быстро, понятно и с фокусом на практику.
Хочется, чтобы приложением мог пользоваться любой человек - независимо от родного языка. Поэтому текста в интерфейсе должно быть как можно меньше. Все подсказки и элементы навигации - максимально визуальные: иконки, картинки, анимации.
Основные задачи:
🔸 тренировка артиклей (der, die, das);
🔸 ведение персональной статистики;
🔸 умный подбор слов, основанный на ошибках и повторениях, а не просто случайной выборке.
Что даст мне этот проект:
🔸 практику в работе с CloudKit 🌧 и синхронизацией данных между устройствами;
🔸 полноценное приложение, которое можно показать в портфолио или друзьям;
🔸 представление о полном цикле разработки: от идеи до релиза;
🔸 уверенность и мотивацию двигаться дальше после первого опубликованного проекта.
Дополнительно:
Я вижу в этом приложении не просто тренировку слов - а возможность выстроить полезную привычку. Каждый короткий сеанс - как шаг в сторону лучшего понимания языка. А ещё это отличная платформа для экспериментов: с UX, дизайном, локализацией и взаимодействием с пользователем (но для этого нужно научиться снимать метрики взаимодействия с приложением).
Самое важное - это должно быть очень простое приложение - с минимальным функционалом и лаконичным дизайном. Никакой перегрузки интерфейса: всё быстро, понятно и с фокусом на практику.
Хочется, чтобы приложением мог пользоваться любой человек - независимо от родного языка. Поэтому текста в интерфейсе должно быть как можно меньше. Все подсказки и элементы навигации - максимально визуальные: иконки, картинки, анимации.
Основные задачи:
Что даст мне этот проект:
Дополнительно:
Я вижу в этом приложении не просто тренировку слов - а возможность выстроить полезную привычку. Каждый короткий сеанс - как шаг в сторону лучшего понимания языка. А ещё это отличная платформа для экспериментов: с UX, дизайном, локализацией и взаимодействием с пользователем (но для этого нужно научиться снимать метрики взаимодействия с приложением).
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Эм.. изучаю CloudKit ☁️ уже несколько часов, только сейчас понял, что private база хранится в квоте пользователя
Но ведь у многих iCloud с дефолтной квотой в 5Gb, и туда ничего не влезает…
Я могу хранить основной набор слов в public базе, потом их синкать и сохранять локально.
❗️ А где сохранять статистику правильных/неправильных ответов пользователя?
Но ведь у многих iCloud с дефолтной квотой в 5Gb, и туда ничего не влезает…
Я могу хранить основной набор слов в public базе, потом их синкать и сохранять локально.
Please open Telegram to view this post
VIEW IN TELEGRAM
Ещё раз про CloudKit
Кажется, я изначально неправильно понял, как работает эта технология.
Основываясь на уроках Hacking with Swift, я предположил, что механизм синхронизации “встроен”. И это действительно так - но только для приватной базы, связанной с конкретным пользователем.
Я думал, что если добавить записи в дашборде CloudKit, они автоматически подтянутся в приложение. И что в коде можно будет как-то отреагировать на приход новых данных, например, callbacks.
Оказалось, что данные из публичной базы нужно явно запрашивать. Никакой “магии” синхронизации тут нет.
Вот пример моей рабочей реализации, которая действительно получает записи, созданные через CloudKit Dashboard:
Ещё в придачу, CloudKit API постоянно устаревает, и код взятый из примеров подсвечивается как deprecated…
#cloudkit
Кажется, я изначально неправильно понял, как работает эта технология.
Основываясь на уроках Hacking with Swift, я предположил, что механизм синхронизации “встроен”. И это действительно так - но только для приватной базы, связанной с конкретным пользователем.
Я думал, что если добавить записи в дашборде CloudKit, они автоматически подтянутся в приложение. И что в коде можно будет как-то отреагировать на приход новых данных, например, callbacks.
Оказалось, что данные из публичной базы нужно явно запрашивать. Никакой “магии” синхронизации тут нет.
Вот пример моей рабочей реализации, которая действительно получает записи, созданные через CloudKit Dashboard:
class CloudKitManager: ObservableObject {
private let database = CKContainer.default().publicCloudDatabase
@Published var words: [WordDto] = []
func fetchWords() {
print("Fetching words from NounWord record type...")
let query = CKQuery(recordType: "NounWord", predicate: NSPredicate(value: true))
let queryOperation = CKQueryOperation(query: query)
var fetchedWords: [WordDto] = []
queryOperation.recordMatchedBlock = { id, result in
switch result {
case .failure(let error):
print("Failed to load word with id \(id): \(error.localizedDescription)")
return
case .success(let record):
guard let word = record["word"] as? String else { return }
guard let articleString = record["article"] as? String else { return }
let dto = WordDto(id: record.recordID.recordName, word: word, article: NounArticle(rawValue: articleString)!, exampleSentences: [])
fetchedWords.append(dto)
}
}
queryOperation.queryResultBlock = { result in
print("Notifying UI about fetched words...")
DispatchQueue.main.async {
switch result {
case .success:
self.words = fetchedWords
case .failure(let error):
print("Error fetching words: \(error.localizedDescription)")
}
}
}
database.add(queryOperation)
}
}
Ещё в придачу, CloudKit API постоянно устаревает, и код взятый из примеров подсвечивается как deprecated…
#cloudkit
🤔1
Что такое Приватная и Публичная базы?
Приватная база привязана к конкретному Apple ID пользователя - данные из неё доступны только этому пользователю. Как раз она синхронизируется между устройствами.
Публичная база, наоборот, общая для всех пользователей приложения - но с ней нужно работать вручную. Т.е. явно отправлять и запрашивать записи, и автоматической синхронизации здесь нет. Она наполняется владельцем приложения.
Есть ещё Shared база, когда пользователь делится данными из приватной базы с другими пользователями. Не мой кейс, поэтому дальше не разбирался.
❗️ это моё текущее понимание
Приватная база привязана к конкретному Apple ID пользователя - данные из неё доступны только этому пользователю. Как раз она синхронизируется между устройствами.
Публичная база, наоборот, общая для всех пользователей приложения - но с ней нужно работать вручную. Т.е. явно отправлять и запрашивать записи, и автоматической синхронизации здесь нет. Она наполняется владельцем приложения.
Есть ещё Shared база, когда пользователь делится данными из приватной базы с другими пользователями. Не мой кейс, поэтому дальше не разбирался.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
По итогу возвращаюсь к Core Data.
Раздумывал между следующими вариантами: Core Data, Realm, SQLite и обёрткой над SQLite - GRDB.
Поскольку с базами я работал за свою профессиональную деятельность много - хочется разобраться с Core Data👍
Раздумывал между следующими вариантами: Core Data, Realm, SQLite и обёрткой над SQLite - GRDB.
Поскольку с базами я работал за свою профессиональную деятельность много - хочется разобраться с Core Data
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Итоги этой недели
🟥 Первая версия приложения DerDieDas уже готова. Она позволяет тренировать слова и посмотреть статистику по ним. Залил в TestFlight.
🟥 Познакомился с основами CloudKit, и даже сделал запросы чтобы вытащить оттуда данные. Но, к сожалению, отказался от него. Хотя технология интересная.
🟥 Перевел с SwiftData на CoreData, т.к. не вижу особых преимуществ.
В CoreData сложнее работать с типами, т.к. фреймворк генерирует поля с базовыми типами, такими как NSSet. Причем, несмотря на отсутствие галочки на Optional чекбоксе, классы генерируются с опциональными полями.
🟥 Для поддержки большего количества устройств, откатил минимальную версию iOS до 15.6
Это повлекло за собой ещё и отказ от
🟥 Внедрил MVVM для главного View (которое содержит артикль, слово и кнопки).
Результат очень даже ничего, код намного чище и логичнее, структурирован так, что его можно протестировать почти без проблем.
В CoreData сложнее работать с типами, т.к. фреймворк генерирует поля с базовыми типами, такими как NSSet. Причем, несмотря на отсутствие галочки на Optional чекбоксе, классы генерируются с опциональными полями.
Это повлекло за собой ещё и отказ от
NavigationStack
(он доступен для iOS 16+) и navigationDestination
в пользу NavigationView
и NavigationLink
в таком виде
NavigationLink(
destination: WordsListView(),
isActive: $showWordsList,
label: { EmptyView() }
)
Результат очень даже ничего, код намного чище и логичнее, структурирован так, что его можно протестировать почти без проблем.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Сейчас структура проекта выглядит так. Всё по полочкам! И без тестов 🙈
Особенно порадовали имена с плюсами у сгенерированных файлов.
Впервые такой подход вижу🙃
Особенно порадовали имена с плюсами у сгенерированных файлов.
Впервые такой подход вижу
Please open Telegram to view this post
VIEW IN TELEGRAM
👏1
This media is not supported in your browser
VIEW IN TELEGRAM
Наконец дошли руки до Metal и шейдеров
Давно хотел разобраться с тем, что такое шейдеры. А тут ещё и на iOS.
Оказывается концепция простая, но очень мощьная. Если кратко, то шейдер это программа выполняемая на GPU, обрабатывающая пиксель или вершину. Обработка идёт в параллель, поэтому всё происходит так быстро.
Основные функции шейдера:
🔸 покрасить пиксель, зная только цвет текущего пикселя
🔸 изменить положение пикселя
Разбирался по статье: https://blog.jacobstechtavern.com/p/metal-in-swiftui-how-to-write-shaders. Доступно и с качественными примерами👍
Эти примеры сделаны на iOS 17, используя iOS 15, всё выходит сильно сложнее, в плане заставить шейдеры отображаться (в статье не описано). Я попробовал самостоятельно, но у меня не получилось заставить MTKView работать. На 17 всё достаточно просто:
#metal #shader
Давно хотел разобраться с тем, что такое шейдеры. А тут ещё и на iOS.
Оказывается концепция простая, но очень мощьная. Если кратко, то шейдер это программа выполняемая на GPU, обрабатывающая пиксель или вершину. Обработка идёт в параллель, поэтому всё происходит так быстро.
Основные функции шейдера:
Разбирался по статье: https://blog.jacobstechtavern.com/p/metal-in-swiftui-how-to-write-shaders. Доступно и с качественными примерами
Эти примеры сделаны на iOS 17, используя iOS 15, всё выходит сильно сложнее, в плане заставить шейдеры отображаться (в статье не описано). Я попробовал самостоятельно, но у меня не получилось заставить MTKView работать. На 17 всё достаточно просто:
view.colorEffect(
ShaderLibrary.glowEdge(
.float(startDate.timeIntervalSinceNow),
.float2(viewSize)
)
)
#metal #shader
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
DerDieDas
Удалось сформировать список слов с примерами, но их корректность нужно проверять⚠️
Для этого написал авторам одного прекрасного сайта, где есть правильная информация по словам, артиклям и т.д. Хочу либо API получить, либо разрешение закроулить эти слова и распарить их html.
Вот пока жду ответа, пробую разные штуки.
Удалось сформировать список слов с примерами, но их корректность нужно проверять
Для этого написал авторам одного прекрасного сайта, где есть правильная информация по словам, артиклям и т.д. Хочу либо API получить, либо разрешение закроулить эти слова и распарить их html.
Вот пока жду ответа, пробую разные штуки.
Please open Telegram to view this post
VIEW IN TELEGRAM
Посмотрел как загрузочные экраны (Splash Screen) делать, выглядит довольно таки просто в реализации, но эффектно 🤩
https://youtu.be/lBCpwYDljwI?si=2SVlHsP6_xxkHYBK
https://youtu.be/lBCpwYDljwI?si=2SVlHsP6_xxkHYBK
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
From Boring to Breathtaking: Mastering SwiftUI Splash Screens for Remarkable App Launches
From Boring to Breathtaking: Mastering SwiftUI Splash Screens for Remarkable App Launches
Mentoring 👉 https://rebeloper.com/mentoring
In this video, we're going to cover everything you need to know about mastering a splash screen for your app launches. From…
Mentoring 👉 https://rebeloper.com/mentoring
In this video, we're going to cover everything you need to know about mastering a splash screen for your app launches. From…
👍1 1
Спешу поделиться со всеми радостной новостью, мне удалось выпустить первое приложение в сторе.
https://apps.apple.com/de/app/derdiedas-de/id6745122637
Маленький, но огромный шаг😎
Буду планировать шаги по реализации своего основного приложения
https://apps.apple.com/de/app/derdiedas-de/id6745122637
Маленький, но огромный шаг
Буду планировать шаги по реализации своего основного приложения
Please open Telegram to view this post
VIEW IN TELEGRAM
App Store
DerDieDas DE
Super simple application to train der/die/das articles for the most common German words.
🔥4👍1
Как я делал скриншоты
Одним из обязательных требований Apple является наличие скриншотов, соответствующих диагонали 6.9 дюйма.
Для этого я использовал симулятор iPhone 16 Pro Max и сделал снимки двух основных экранов приложения.
Где-то пишут, что требуется скриншот для iPad, но ревью пройденно без них.
После этого загрузил изображения на theapplaunchpad.com, чтобы добавить фон и надписи.
Существуют и другие подобные сервисы, но большинство из них платные. Этими изображениями удалось воспользоваться бесплатно.
Одним из обязательных требований Apple является наличие скриншотов, соответствующих диагонали 6.9 дюйма.
Для этого я использовал симулятор iPhone 16 Pro Max и сделал снимки двух основных экранов приложения.
Где-то пишут, что требуется скриншот для iPad, но ревью пройденно без них.
После этого загрузил изображения на theapplaunchpad.com, чтобы добавить фон и надписи.
Существуют и другие подобные сервисы, но большинство из них платные. Этими изображениями удалось воспользоваться бесплатно.
👍1
Всем привет! 👋 Хочу поделиться забавной историей.
Недавно собрал фидбэк по приложению для артиклей у знакомых. Одно из предложений было подсвечивать слова в предложениях.
Для этого исходное предложение нужно разбить на слова, и что самое главное найти это слово вместе с артиклем. Осложняется это тем, что в зависимости от падежа и рода существительного, артикль может меняться.
Так вот пообщавшись с моим другом с утреца📱 получил от него идею воспользоваться spaCy - Python библиотека для NLP (Обработка естественного языка). Инструмент действительно хороший, но не без ошибок.
А вечером я пошёл на мини-конференцию по Python👩💻
Расписание я подробно посмотрел буквально перед входом - и был приятно удивлён, т.к. первый же докладчик была CEO из компании, которая занимается разработкой spaCy.
Я просто не мог уйти без их стикер🔥
Недавно собрал фидбэк по приложению для артиклей у знакомых. Одно из предложений было подсвечивать слова в предложениях.
Для этого исходное предложение нужно разбить на слова, и что самое главное найти это слово вместе с артиклем. Осложняется это тем, что в зависимости от падежа и рода существительного, артикль может меняться.
Так вот пообщавшись с моим другом с утреца
А вечером я пошёл на мини-конференцию по Python
Расписание я подробно посмотрел буквально перед входом - и был приятно удивлён, т.к. первый же докладчик была CEO из компании, которая занимается разработкой spaCy.
Я просто не мог уйти без их стикер
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1😁1
Сегодня смотрел как правильно вносить изменения в модели CoreData.
В текущей модели у меня предложения представлены массивом, который хранится в Core Data напрямую.
Переделал так, что каждое предложение представляет собой набор токенов (слово или знак препинания) и индексы токенов, которые нужно будет подсветить.
Наивным путём удалил одно поле и добавил другое😮
В симуляторе и на телефоне отработало идеально. Но вот с preview всё сломалось. Ни перезагрузка, ни очистка рабочих директорий - ничего не помогало.
🚫 Ошибка была вида: Persistent store migration failed, missing mapping model
Ну и насколько я понял, нужно было создать новую версию модели. Сделал так. Получается в проекте теперь хранятся обе модели.
Сейчас всё снова работает как часы! ⏰
В текущей модели у меня предложения представлены массивом, который хранится в Core Data напрямую.
Переделал так, что каждое предложение представляет собой набор токенов (слово или знак препинания) и индексы токенов, которые нужно будет подсветить.
Наивным путём удалил одно поле и добавил другое
В симуляторе и на телефоне отработало идеально. Но вот с preview всё сломалось. Ни перезагрузка, ни очистка рабочих директорий - ничего не помогало.
Ну и насколько я понял, нужно было создать новую версию модели. Сделал так. Получается в проекте теперь хранятся обе модели.
Сейчас всё снова работает как часы! ⏰
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Please open Telegram to view this post
VIEW IN TELEGRAM
Вау 😯 Рассказывает дочка Пола из hackingwithswift про неочевидные вещи в swift (не сложные, но забавные), ей всего 15, а уже на сцене. Невероятный буст мотивации!
https://www.youtube.com/watch?v=dQJUoNIbDsg
Как быстро растут чужие дети 🥲
https://www.youtube.com/watch?v=dQJUoNIbDsg
Как быстро растут чужие дети 🥲
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Swift WTF – Surprising behaviors while learning Swift
Swift is a smart, modern programming language that makes it easy to build a wide range of software, but if you're not careful it's easy to run into some surprising behaviors. In this video you'll learn about a few of them, and I'm pretty sure everyone will…
Когда опыт не спасает от неуверенности
Будучи синьёром 🍅 backend разработчиком, я привык понимать, почему код устроен так или иначе. Привык сразу закладывать масштабируемость, отказоустойчивость, где нужно, думать о поддержке и развитии проекта.
Сейчас я изучаю iOS и SwiftUI. Почти каждый шаг сопровождает меня сомнениями.
Управление состоянием, архитектура, тестирование, переходы и способы навигации - всё непривычно. Да, код работает, приложение запускается. Но внутри постоянное ощущение, что я делаю что-то не так, не по принятым стандартам, что-то упускаю, где-то закладываю потенциальные проблемы.
Несмотря на то, что ловлю себя на мысли, что так и должно быть, это неприятное ощущение сопровождает меня. Конечно, это нормально, будучи в начале пути совершать ошибки. Да даже и где-то посреди, это тоже неизбежно. Осознаю, понимаю, но бороться с этим не так уж просто.
Ну хватит ныть! Главное - продолжаем, с выводами по пути (и неприятными тоже), но движемся вперед!
Возможно среди вас есть те, кто прошел через это, и, естественно, те, кто только будет проходить. Не забываем, что это временно💪
Будучи синьёром 🍅 backend разработчиком, я привык понимать, почему код устроен так или иначе. Привык сразу закладывать масштабируемость, отказоустойчивость, где нужно, думать о поддержке и развитии проекта.
Сейчас я изучаю iOS и SwiftUI. Почти каждый шаг сопровождает меня сомнениями.
Управление состоянием, архитектура, тестирование, переходы и способы навигации - всё непривычно. Да, код работает, приложение запускается. Но внутри постоянное ощущение, что я делаю что-то не так, не по принятым стандартам, что-то упускаю, где-то закладываю потенциальные проблемы.
Несмотря на то, что ловлю себя на мысли, что так и должно быть, это неприятное ощущение сопровождает меня. Конечно, это нормально, будучи в начале пути совершать ошибки. Да даже и где-то посреди, это тоже неизбежно. Осознаю, понимаю, но бороться с этим не так уж просто.
Ну хватит ныть! Главное - продолжаем, с выводами по пути (и неприятными тоже), но движемся вперед!
Возможно среди вас есть те, кто прошел через это, и, естественно, те, кто только будет проходить. Не забываем, что это временно
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Немного о прогрессе и успехах
Получил позитивный фидбэк, с элементами критики и предложений по улучшению от преподавателя немецкого языка.
У меня двоякое ощущение, т.к. одно из названных достоинств было - простота, а новые фичи такие, что сильно усложнят интерфейс. Как быть дальше🤔
➖ ➖ ➖
Пока в голове я ношу и перевариваю идею как будет выглядеть приложение - трекер товаров. То как я хочу его видеть, понимаю, что технически будет очень сложно реализовать. Моего опыта явно не хватит. А из предыдущего поста, как вы могли заметить, я хочу сделать всё относительно правильно 😁
Получил позитивный фидбэк, с элементами критики и предложений по улучшению от преподавателя немецкого языка.
У меня двоякое ощущение, т.к. одно из названных достоинств было - простота, а новые фичи такие, что сильно усложнят интерфейс. Как быть дальше
Пока в голове я ношу и перевариваю идею как будет выглядеть приложение - трекер товаров. То как я хочу его видеть, понимаю, что технически будет очень сложно реализовать. Моего опыта явно не хватит. А из предыдущего поста, как вы могли заметить, я хочу сделать всё относительно правильно 😁
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Мультиэкран без навигации
Обнаружил интересный подход к построению приложения с несколькими экранами, но без навигации.
Выглядит очень удобно для небольших приложений, где всю логику можно уместить в стейт машину.
Основная идея - иметь одно вью, которое меняет своё отображение в зависимости от текущего состояния.
😎 На счет перформанса не уверен, но для квиз подобных приложений удобно!
Обнаружил интересный подход к построению приложения с несколькими экранами, но без навигации.
Выглядит очень удобно для небольших приложений, где всю логику можно уместить в стейт машину.
Основная идея - иметь одно вью, которое меняет своё отображение в зависимости от текущего состояния.
struct WordsGameView: View {
@StateObject private var viewModel = WordsGameViewModel()
var body: some View {
ZStack {
switch viewModel.currentScreen {
case .welcome:
WelcomeView {
viewModel.startQuiz()
}
case .question(let question):
QuestionView(question: question) { answer in
viewModel.submit(answer: answer)
}
case .result(let result):
ResultView(result: result) {
viewModel.goToMainMenu()
}
case .mainMenu:
MainMenuView {
viewModel.startQuiz()
}
}
}
.animation(.none, value: viewModel.currentScreen)
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1