Kotlin/NativeがBetaの頃から業務で使い続けているので、Tipsを書いていこうと思います。
随時更新予定。
iOSの場合は実機よりシミュレータの方がコンパイル時間が短い
Kotlin/NativeのコンパイラはiOS Simulatorに最適化されているので、基本はシミュレータで開発した方がいいです。
コンパイラの動作を遅くしていたいくつかの問題を解消することで、コンパイル時間を改善しました。コードに変更を加えた後、iOS Simulatorをターゲットにしたバイナリを再コンパイルするのに必要な時間を最小限に抑えることに重点を置いたため、iOS Simulator上でユニットテストやアプリケーションを再実行したときに最も大きな改善が見られます。例えば、KMMのネットワーキングとデータストレージのサンプルでは、フレームワークの再構築にかかる時間を、9.5秒(1.4.10)から4.5秒(1.4.30)に短縮しました。
特定のケースに焦点を当てていますが、ほとんどの最適化は他のシナリオにも影響します。
今後もコンパイラーの最適化を続けていく予定です。
「kotlin.native.concurrent.InvalidMutabilityException」対策
概要については以下の公式サイトを参照してください。
https://kotlinlang.org/docs/mobile/concurrent-mutability.html#atomicint-atomiclong
解決策としては、touchlab/Statelyというライブラリを使えばよいです。
このライブラリを使うことで、複数のスレッドから変数の値を変更できるようになります。
Xcodeの「Validate Workspace」をYesにする
Xcodeで「Validate Workspace」をYesにすると、ビルド対象のデバイス(シミュレータ or 実機)を切り替えた時に、自動でsharedコードをリビルドするようになります。
String.formatを使う
expect/actualを使えばできます。
expect fun stringFormat(format: String, vararg args: Any?): String
actual fun stringFormat(format: String, vararg args: Any?): String {
return String.format(format, *args)
}
// https://stackoverflow.com/a/64499248/4791194
actual fun stringFormat(format: String, vararg args: Any?): String {
var returnString = ""
val regEx = "%[\\d|.]*[sdf]|[%]".toRegex()
val singleFormats = regEx.findAll(format).map {
it.groupValues.first()
}.asSequence().toList()
val newStrings = format.split(regEx)
for (i in 0 until args.count()) {
val arg = args[i]
returnString += when (arg) {
is Double -> {
NSString.stringWithFormat(newStrings[i] + singleFormats[i], args[i] as Double)
}
is Int -> {
NSString.stringWithFormat(newStrings[i] + singleFormats[i], args[i] as Int)
}
else -> {
NSString.stringWithFormat(newStrings[i] + "%@", args[i])
}
}
}
if (newStrings.count() > args.count()) {
returnString += newStrings.last()
}
return returnString
}
class CommonTest {
@Test
fun testStringFormat() {
assertEquals("test: a", stringFormat("test: %s", "a"))
assertEquals("1, 2", stringFormat("%d, %d", 1, 2))
}
}