Irbisa · Шпаргалка
Interop KMP и Swift
ObjC-мост, suspend и Flow в Swift, SKIE, XCFramework, SPM, линковка, Swift export
Как типы Kotlin выглядят в Swift через Objective-C-мост: числа, nullable-примитивы, коллекции, nullability?
class FeedApi { fun page(size: Int, cursor: Long?): List<Post> = TODO() fun unreadCount(): Int? = null fun ratings(): List<Int> = listOf(5, 4)}…Что происходит с дженериками Kotlin при переходе через Objective-C-мост и почему общий интерфейс
Result<T>доходит до Swift какAny?Как iOS-команда вызывает из Swift каждое из этих Kotlin-объявлений?
// Greeting.kt in the shared frameworkobject Analytics { fun track(event: String, params: Map<String, String> = emptyMap()) {}} data class User(val id: Long, val name: String) class Loader { fun load(id: Long): User = TODO() fun load(id: String): User = TODO()} fun greet(user: User): String = "Hi, ${user.name}"Почему
switchв Swift по sealed-классу Kotlin требует веткуdefaultи как вернуть исчерпывающую проверку?sealed interface AuthState { data object Anonymous : AuthState data class LoggedIn(val token: String) : AuthState data class Failed(val reason: String) : AuthState}…Как Kotlin
suspend funвыглядит из Swift и что происходит, когда Swift отменяетTask, который её ждёт?class Subscription(private val job: Job) { fun cancel() = job.cancel()} class UserFacade(private val api: UserApi) { private val scope = MainScope()…Найдите баг: когда сервер отвечает 404, iOS-приложение падает вместо того, чтобы показать ошибку из блока
catchв Swift.class ApiException(val code: Int) : Exception("HTTP $code") class ProfileRepository(private val client: HttpClient) { // Swift: do { try await repo.loadProfile(id: 42) } catch { show(error) } suspend fun loadProfile(id: Long): Profile { val response = client.get("profiles/$id") if (!response.status.isSuccess()) { throw ApiException(response.status.value) } return response.body() }}Как потреблять Kotlin
Flowиз Swift и что дают KMP-NativeCoroutines и SKIE по сравнению с самописной обёрткой?class Subscription(private val job: Job) { fun cancel() = job.cancel()} class PostFacade(private val repo: PostRepo) { private val scope = MainScope()…Что на самом деле генерирует SKIE и чего стоит его подключение для сборки?
Как в Swift 6 со strict concurrency держать общий Kotlin-ViewModel в SwiftUI и обновлять UI только на главном потоке?
import SwiftUIimport Shared @MainActor@Observablefinal class FeedModel {…Эта модель собирает общий Kotlin
StateFlowчерез SKIE. Почему ни она, ни Kotlin-ViewModel никогда не освобождаются?@MainActorfinal class FeedModel: ObservableObject { @Published var posts: [Post] = [] private let vm = FeedViewModel() // Kotlin, exported via SKIE init() { Task { [weak self] in guard let self else { return } for await list in self.vm.posts { self.posts = list } } }}Как спроектировать публичный API общего модуля, чтобы SwiftUI-код поверх него читался как Swift?
class Subscription(private val job: Job) { fun cancel() = job.cancel()} object SharedFactory { fun feedViewModel(): FeedViewModel = FeedViewModel(provideFeedRepo()) // internal constructor stays hidden…Как общий фреймворк попадает к iOS-команде со своим репозиторием и без JDK и чего стоит каждый способ доставки?
kotlin { val xcf = XCFramework("Shared") // one artifact, every iOS slice listOf(iosArm64(), iosSimulatorArm64()).forEach { target -> target.binaries.framework { baseName = "Shared" isStatic = true…Статический или динамический фреймворк для общего модуля: что меняется для времени запуска, размера приложения, расширений и символов крэшей?
Брейкпоинт в
.kt-файле не срабатывает из Xcode, а значения Kotlin видны как непрозрачные объекты. Что нужно, чтобы отлаживать через границу?# Xcode > Build Phases > Run Script: the variant follows CONFIGURATIONcd "$SRCROOT/.."./gradlew :shared:embedAndSignAppleFrameworkForXcode# Exporting KOTLIN_FRAMEWORK_BUILD_TYPE=release in a Debug scheme# is one common reason breakpoints stop working.…Что меняет Swift export в Kotlin по сравнению с Objective-C-мостом и выпустили бы вы на нём релиз сегодня?
// shared/build.gradle.ktskotlin { iosArm64() iosSimulatorArm64() swiftExport {…