Kotlin Native iOS字符串格式与vararg

问题描述

基于this issue关于使用Nsstring格式的信息,我尝试在使用vararg时实现用于格式化的多平台实现,到目前为止还算没有运气。

我做了

  • 添加了FoundationInterop.def
language = Objective-C
---
#import <Foundation/Nsstring.h>

Nsstring* format(Nsstring* format,...) {
    va_list args;
    va_start(args,format);
    Nsstring* result = [[Nsstring alloc] initWithFormat:format arguments:args];
    va_end(args);
    return result;
}
  • 将其编译为gradle
targets {
        final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos")  \
         ? presets.iosArm64 : presets.iosX64

        // https://kotlinlang.org/docs/reference/mpp-dsl-reference.html#native-targets
        fromPreset(iOSTarget,'ios') {
            binaries {
            }

            compilations.main.cinterops {
                FoundationInterop {
                }
            }
        }
    }
  • StringExtensions.kt中创建了commonMain
expect class StringType

expect fun String.format(format: String,vararg args: Any?): StringType?
  • iosMain
actual typealias StringType = String

/**
 * https://github.com/JetBrains/kotlin-native/issues/1834
 */
actual fun String.format(format: String,vararg args: Any?): StringType? {
    return FoundationInterop.format(format,args as Any)
}
  • 示例
val fmt = "http://geomag.bgs.ac.uk/web_service/GMModels/igrf/13/?latitude=%f&longitude=%f&altitude=0&date=%d-%02d-%02d&format=json"
val url = fmt.format(urlFmt,59.127934932762166,38.00503518930868,2020,1,3)
  • 输出-如您所见,由于某种原因没有发生值替换
http://geomag.bgs.ac.uk/web_service/GMModels/igrf/13/?latitude=0.000000&longitude=0.000000&altitude=0&date=43344272-198763328-00&format=json

修改

stringWithFormat给出相同的结果

actual fun String.format(format: String,vararg args: Any?): StringType? {
    return Nsstring.stringWithFormat(format,args as Any)
}

编辑2

创建的问题https://youtrack.jetbrains.com/issue/KT-42925

解决方法

我确认您对NSString.stringWithFormat的看法。正如我们在JB官方解答中所读到的那样,该功能缺失 Svyatoslav Scherbina,我们可以在这里关注您的问题:KT-42925

作为一个可怕的解决方法,我建议使用类似的方法(警告:不详尽,没有很多索引计数检查...)

import platform.Foundation.NSString
import platform.Foundation.stringWithFormat

actual typealias StringType = String

actual fun String.format(format: String,vararg args: Any?): StringType? {
    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])
            }
        }
    }

    return returnString
}

但是请看它是否对您来说是有效的解决方法。

enter image description here

,

您不能将Kotlin可变参数传递给C或Objective-C。 C variadics是编译时间。 这不是Kotlin特有的限制。您不能通过转发所有参数而从另一个可变C函数调用可变C函数。

NSString.stringWithFormat(format,args as Any)

这是不正确的。 该行使用args(是Array),将其强制转换为Any并作为单个参数传递。

所以这基本上等同于类似的东西

[NSString stringWithFormat:format,createKotlinArray(/* all arguments here */)]

它没有达到您的期望。

因此KT-42925无效。 您的问题可能由缺少的功能之一解决了:

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...