Kotlin/Swift (iOS) Туда и Обратно
36 subscribers
127 photos
21 videos
9 files
84 links
Канал - журнал, рассказывающий об опыте изучения Swift & iOS backend-разработчиком на Java & Kotlin
Download Telegram
Проект 14 (День 69)

1️⃣ Добрались до карт 🗺 используем MapKit.

Я приятно удивлён с какой лёгкостью они интегрируются в приложение:

Map {
ForEach(locations) { location in
Marker(location.name, coordinate: location.coordinate)
}
}
.mapStyle(.hybrid)


Похоже, что мы ограничены только своей фантазией. С ними можно делать что угодно. Размещать SwiftUI компоненты поверх, пожалуй, самое простое из этого.

2️⃣ Touch ID & Face ID 🔒

Всё что нужно - это вежливо попросить. Остальное iOS сделает за нас.


func authenticate() {
let context = LAContext()
var error: NSError?

if context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
) {
let reason = "Любимые места - это маленький секрет"

context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: reason
) { success, authenticationError in
if success {
isUnlocked = true
}
}
}
}


Кстати, почему есть отдельный тип для Pointer? Я ожидал увидеть *, как в 👩‍💻

@available(iOS 8.0, *)
open func canEvaluatePolicy(_ policy: LAPolicy, error: NSErrorPointer) -> Bool


#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Только сейчас заметил, что порядок параметров строго зафиксирован 😕

Если есть такая структура:

struct Location: Codable, Equatable, Identifiable {
let id: UUID
var name: String
var description: String
var latitude: Double
var longitude: Double
}


То такой код не работает:

Location(id: UUID(), description: "", latitude: 0, longitude: 0, name: "name")

name должен стоять ровно между id & description

После работы с Kotlin, свободный порядок именованных параметров кажется интуитивно очевидным, но это не так.
Please open Telegram to view this post
VIEW IN TELEGRAM
Media is too big
VIEW IN TELEGRAM
Сегодня продуктивный день! Проект 14 (День 70)

Даже не знаю про что тут рассказать. В основном использовали изученое ранее, просто собрали всё вместе.

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

Image()
.onLongPressGesture {
selectedPlace = location
}


Переделал так, заработало:

Image()
.simultaneousGesture(LongPressGesture(minimumDuration: 1).onEnded { _ in selectedPlace = location })


Не знаю точно, но возможно карта перехватывает жест в первом случае.

Это можно как-то затрейсить логами или отдебажить?

#hackingwithswift
Ах да, была такая штука - @escaping

Чтобы вернуть из EditView новый объект, доступный в callback onSave, сделали конструктор:

init(location: Location, onSave: @escaping (Location) -> Void) {
self.location = location
self.onSave = onSave

_name = State(initialValue: location.name)
_description = State(initialValue: location.description)
}


Использовали @escaping, чтобы сказать компилятору - “будем вызывать это замыкание потом, не в этом методе”.
Насколько понял, этот механизм переносит замыкание из стека в heap. При этом важно не ссылаться на self.
🤔1
Kotlin/Swift (iOS) Туда и Обратно pinned «Сколько iOS разработчиков среди нас? 🤔»
Media is too big
VIEW IN TELEGRAM
Проект 14 (Дни 72 и 73) - финальный аккорд.

Не так уж много осталось:

🟢 Запросы к Wikipedia API, чтобы получить список мест рядом. И я проявил супер креативность 😊 - имя метки берёт title первого результата.

🟢 Сортировка списка мест, полученных из Wikipedia.

🟢 MVVM - слышал и читал про этот подход, когда делал десктопное приложение на Java. SwiftUI справляется гораздо лучше, т.к. он по-умолчанию “реактивный”.
Пока до тестов не добрался - всей прелести не увидел, но могу уже представить.

🟢 Face ID - его мы просто реализовали так же как и ранее (в подготовительном уроке). Тема раскрыта в одном из предыдущих постов.

#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Для сравнения списков мест использовали такой подход:

struct Page: Codable, Comparable {
let pageid: Int
let title: String
let terms: [String: [String]]?

var description: String {
terms?["description"]?.first ?? "No further information"
}

static func <(lhs: Page, rhs: Page) -> Bool {
lhs.title < rhs.title
}
}


Я думаю, что он неправильный, а точнее не совсем корректный.

Если взять два объекта с title = “a”, в таком случае мы получим:

print(p1 < p2) // false
print(p2 < p1) // false
print(p1 == p2) // false


В документации сказано, что так же нужно реализовывать ==, тогда этого недоразумения быть не должно. Печально, что автор об этом не говорит. Хотя я спросил у ChatGPT 💬 об этом, он утверждает, что реализация без == - корректная 😄

В Java это реализовано удачнее, на мой взгляд, результатом сравнения является int, который может принимать:
➡️ отрицательные значения если меньше
➡️ положительные значения если больше
➡️ ноль если равно

Реализовывать нужно всего один метод. Да, использование выглядит не так красиво (сравнение вида a.compareTo(b) >= 0, но Kotlin это исправляет и позволяет писать a >= b.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Вот, кстати, выдержка из документации
https://developer.apple.com/documentation/swift/comparable
👨‍💻1
Всем привет! Закончил Проект 15 (дни 74, 75, 76)

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

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

#hackingwithswift
👍2
Тест на этот раз был очень хороший! Вопросы довольно таки хорошо раскрывают тему 💪
Делаю челлендж по дням 77 и 78

Пришлось сделать небольшой перерыв, но я вернулся 😉

Пока испытываю трудности с организацией вьюх при нажатии на плюсик - учусь работать с асинхронными данными корректно
PhotosPicker долго загружает фото. Сейчас ContentView перегружен функционалом, и вывод списка, и добавление новой записи, и выбор фото… 🤯
Размышляю как это декомпозировать.

Завтра планирую сделать рабочую версию, поэтому буду писать больше 🧑‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
От этого начинает уже иногда глаз дёргаться.

Проблема
Если у меня в определении sheet есть ошибка, то я вижу Ambiguous use of ‘toolbar(content:)’

Как решаю сейчас
В какой-то момент я понял, что с тулбаром всё в порядке. А как решение можно его закомментить и смотреть реальную ошибку.

Как это должно правильно решаться?
Подскажите кто знает, пожалуйста, я трачу реально много времени на это. Переместить тулбар вниз/наружу не получилось, т.к. он привязан к List, который находится внутри NavigationStack. Возможно стоит sheet на один уровень с toolbar перенести?
This media is not supported in your browser
VIEW IN TELEGRAM
Во время реализации столкнулся с таким странным поведением. Sheet не видел изменения в selectedImage, до тех пор пока не будет введен символ в TextField.
Пофиксил созданием отдельного View для добавления.
Пока ещё загадок для меня слишком много 😱 Последовательно будем разбираться!
Please open Telegram to view this post
VIEW IN TELEGRAM
👨‍💻1
Media is too big
VIEW IN TELEGRAM
По итогу получилось приложение в котором можно взять фото из галереи и добавить ему имя. Автоматически подтягивается последняя известная локация.

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

Тут я дополнительно посмотрел
- как делать фокус на конкретных полях (в данном случае имя записи получает фокус)
- TabView, чтобы переключаться между списком и картой
🔥1
Проект 16 (день 79)

После проекта, сделанного в рамках челенжа, мне не терпится поскорее пройти курс дальше! Небольшой, но, как всегда, полезный урок:

🟢 Выбор нескольких элементов в списке. Активируется либо горизонтальным свайпом 2-мя пальцами, либо добавлением кнопки EditButton

🟢 TabView - пришло его время, но я уже использовал его в челенже ✌️ Концепция вполне простая, но очень полезная. Вижу почти в каждом приложении.

#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Обратил внимание только сейчас.

Загруженное изображение как UIImage(systemName), а потом переданное в 👶 Image становится пиксельным.

Если использовать Image(systemName), то получается векторное изображение, красивое при любом разрешении.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1🤔1
Проект 16 (день 80)

Сегодня тоже не много тем, точнее они не очень объемные, но они не становятся менее интересными:

🟢 Result - тип похожий на Either из функциональных языков. Может содержать в себе либо success, либо failure. В Kotlin такой тоже есть.

🟢 Интерполяция изображений - у Image есть interpolation расширение, можно настроить степень интерполяции. Если простыми словами, это дорисовать новые пиксели на основе существующих при увеличении изображения.

🟢 Контекстные меню - при нажатии на элемент (удерживая палец) можно вызвать меню. Автор рекомендует им не увлекаться, т.к. такой функционал не очень очевиден пользователям.
Кстати, на маке в Swift Playground это не работает, видимо только для тачскринов.

#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1