Почините общий Kotlin API, который команде iOS неудобно вызывать из Swift
Этот общий код компилируется, и Android им доволен, но команда iOS сообщает о двух проблемах: из Swift приходится передавать в search все аргументы, а switch по SearchResult всё равно требует ветку default, хотя перечислены все случаи.
Ограничение: правка обязана остаться внутри общего модуля. Не просите команду iOS писать обёртку на Swift и не включайте альфа-возможности компилятора.
// commonMain
sealed class SearchResult {
data class Hits(val items: List<String>) : SearchResult()
data object Empty : SearchResult()
data class Failed(val reason: String) : SearchResult()
}
class SearchApi {
fun search(query: String, page: Int = 0, pageSize: Int = 20): SearchResult = TODO()
}
Определите причину и исправьте.
Kotlin/Native экспортирует через Objective-C-заголовок, а в Objective-C нет ни аргументов по умолчанию, ни исчерпывающих сумм: Swift требует все параметры и всё равно просит default. Добавьте явные перегрузки и дискриминатор, по которому switch исчерпывающий.
- ✗Ждать, что аргументы по умолчанию Kotlin доживут до Objective-C-заголовка
- ✗Считать, что
sealed classостаётся исчерпывающим дляswitchв Swift - ✗Хвататься за
@JvmOverloads— это JVM-аннотация, на Kotlin/Native она ничего не делает
- →Что происходит с
suspend-функцией, когда она переходит в Objective-C-заголовок? - →Как сохранить удобный Kotlin API для Android и всё же экспортировать удобный для Swift?
Что происходит
Kotlin/Native экспортирует общий модуль в iOS через сгенерированный Objective-C-заголовок. Swift читает именно его. Objective-C не знает двух вещей из объявления выше:
- аргументов по умолчанию — метод один, и все параметры в нём обязательны;
- исчерпывающих сумм —
sealed classприезжает набором обычных классов, поэтому компилятор Swift не может доказать полнотуswitchи требуетdefault.
@JvmOverloads тут бесполезен: это JVM-аннотация, на Kotlin/Native она не действует.
Правка
// commonMain
enum class SearchOutcome { HITS, EMPTY, FAILED }
class SearchResult private constructor(
val outcome: SearchOutcome,
val items: List<String>,
val reason: String?,
) {
companion object {
fun hits(items: List<String>) = SearchResult(SearchOutcome.HITS, items, null)
fun empty() = SearchResult(SearchOutcome.EMPTY, emptyList(), null)
fun failed(reason: String) = SearchResult(SearchOutcome.FAILED, emptyList(), reason)
}
}
class SearchApi {
fun search(query: String): SearchResult = search(query, 0, 20)
fun search(query: String, page: Int): SearchResult = search(query, page, 20)
fun search(query: String, page: Int, pageSize: Int): SearchResult = TODO()
}
Явные перегрузки заменяют аргументы по умолчанию, а enum даёт Swift дискриминатор, по которому switch действительно исчерпывающий. Android при этом ничего не теряет — при желании удобный Kotlin-API остаётся отдельным слоем поверх.