Kotlin/Swift (iOS) Туда и Обратно
36 subscribers
127 photos
21 videos
9 files
84 links
Канал - журнал, рассказывающий об опыте изучения Swift & iOS backend-разработчиком на Java & Kotlin
Download Telegram
Чтобы работали и SwiftData, и JSONDecoder, нужно сделать такие страшные вещи 😱
Написать кастомные encoder/decoder методы.
Please open Telegram to view this post
VIEW IN TELEGRAM
😱2
Проект 13 (Day 62) - состоит аж из 6 частей. Обычно проект состоит из 3. Буду его дробить на части поменьше.

🟢 Заглянули во внутренности State проперти враппера. Но не настолько сильно, чтобы понять как он работает на 100%. Однако эти детали помогают понять почему этот код не работает при изменении поля через bindings:

@State private var blurAmount = 0.0 {
didSet {
print("New value is \(blurAmount)")
}
}


🟢 onChange - позволяет подписаться на любые изменения переменной

Slider(value: $blurAmount, in: 0...20)
.onChange(of: blurAmount) { oldValue, newValue in
print("New value is \(newValue)")
}


🟢 confirmationDialog - диалоговое окно похожее на alert, но мне оно кажется функциональнее, т.к. оно и его кнопки находятся внизу, что позволяет быстрее и легче взаимодействовать с ним (не нужно тянуться пальцем к середине экрана, как в случае с `alert`).

#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Проект 13 (Day 63)

Сегодня были 2 темы. Порой это сильно удивляет, насколько малосвязанные темы включаются в один урок.

🟢 CoreImage - оказывается, для представления изображений в iOS есть четыре основных типа:
🟠 SwiftUI Image - View для отображения изображений в SwiftUI.
🟠 UIImage - изображение из UIKit. Обширный функционал, поддерживает форматы PNG, SVG и другие.
🟠 CGImage - Core Graphics. По сути двумерный массив пикселей.
🟠 CIImage - Core Image. Автор называет его “рецептом для создания изображения”. Поддерживает различные фильтры, такие как pixellate, crystallize, sepiaTone и другие.

🟢 ContentUnavailableView - view с иконкой, текстом и кнопкой (которые можно кастомизировать по своему усмотрению), предназначенное для отображения, когда контент недоступен.

#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
Проект 13 (Day 64)

Следующий урок закончил! 2 за 1 день - достойно похвалы, пойду съем по этому случаю яблоко 👩‍💻

Сегодня в программе:
🟢 Выбор изображения из библиотеки фото. Делается это с помощью PhotosPicker. Однозначно мне пригодится!

🟢 ShareLink - конфигурируемый элемент, чтобы вызвать диалоговое окно share. Думаю все и так знают что это такое.

🟢 @Environment(\.requestReview) var requestReview - попросить пользователя оставить отзыв. Вызывается как функция requestReview().
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Стало интересно что такое requestReview.
Это инстанс структуры RequestReviewAction определенной как:

// Available when SwiftUI is imported with StoreKit
@available(iOS 16.0, visionOS 1.0, macOS 13.0, *)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@MainActor public struct RequestReviewAction {

@MainActor public func callAsFunction()
}


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

В Kotlin тоже есть такой функционал, выглядело бы это так:

class RequestReviewAction {
operator fun invoke() {
println("Requesting review...")
}
}

fun main() {
val requestReview = RequestReviewAction()
requestReview()
}


Что такое @MainActor ещё предстоит узнать #todo
👍2
Kotlin/Swift (iOS) Туда и Обратно
Какой подход вам ближе?
После жарких дебатов наш консилиум решил оставить callAsFunction. Петиция в Apple 👩‍💻 отправлена в архив, страница с жалобами - удалена.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Проект 13 (Day 65) - объединение изученного!

Сегодня добавили основные UI элементы приложения, а так же реализовали изменение интенсивности фильтра.
Дальше добавим возможность менять фильтры.

Использование и конвертация [CI, CG, UI, ]Image, как неоднократно подмечалось автором, выглядит монструозно 🤯
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Решать задачи на leetcode 👩‍💻 используя Swift сложнее потому, что ошибки просто нечитаемые. Конкретно эта ошибка - доступ по индексу больше чем размер массива.
Если смотреть как оптимист, то это то, что нужно, ведь приходится в голове продебажить код и найти ошибку 😃

В Xcode такое встретить тоже можно 🫠
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Закончил Проект 13 🥳

Последним штрихом была поддержка других фильтров, и выбор активного среди них. А так же реализация share функционала.

Работа с изображениями мне нравится, и теперь это в моём ящике с инструментами! Держись фотошоп, я иду 📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Прошёл тест, результат очень радует
🔥2💯1
День 68 и это новый Проект 14. Сегодня начинаем разработку приложения-трекера мест, которые хотим посетить.

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

🟢 Comparable - протокол, позволяющий использовать операторы <, <=, >= и >. Полезен, если нужно сравнивать объекты собственного типа. Документация.

🟢 URL.documentsDirectory - тут приложение может сохранить свои файлы. Должно синхронизоваться с iCloud.
Можно представить его как кладовку: складывать туда удобно, но лучше не забывать наводить порядок, иначе потом найдётся куча старых ненужных файлов, как в ящике с носками. 🧦

🟢 Выбор View через значение enum. Не лучший вариант с точки зрения полиморфизма, но зато просто и наглядно:


var body: some View {
switch loadingState {
case .loading:
LoadingView()
case .success:
SuccessView()
case .failed:
FailedView()
}
}


#hackingwithswift
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Проект 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