Kotlin Native iOS 字符串格式化与可变参数
Posted
技术标签:
【中文标题】Kotlin Native iOS 字符串格式化与可变参数【英文标题】:Kotlin Native iOS string formatting with vararg 【发布时间】:2021-02-06 05:37:16 【问题描述】:基于this issue关于使用NSString
格式化我尝试在使用vararg
时实现格式化的多平台实现,到目前为止没有运气。
我做了什么
添加了 FoundationInterop.deflanguage = 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
在commonMain
中创建StringExtensions.kt
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
【问题讨论】:
不是您的问题的答案,我想检查它为什么不起作用,但您提供的问题现已关闭:从 1.3.40 开始,可以直接使用initWithFormat
.
@shadowsheep 感谢您指出这一点,但它也不起作用,请参阅我的编辑
@shadowsheep 这个方法在我们传递像NSString.stringWithFormat("%@ %@ %d", "один" as NSString, "two" as NSString, 3)
这样的参数时有效,但不适用于vararg
知道了。现在更清楚了;)。所以我可以建议“格式化”你的格式和你的可变参数,以便函数相应地工作,在 iOS 内部真正有趣。
@shadowsheep 会是什么样子?
【参考方案1】:
我确认你所说的 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
但是看看它是否对你来说是一个有效的解决方法。
【讨论】:
感谢您的回答,这是一个有趣的解决方法,我会等待一段时间,也许会出现其他解决方案,如果没有,我会除了您的回答,这是我们应该重新发明***的痛苦Kotlin Native 来做这些基本的事情。顺便说一句,也许您知道一些已经具有多平台字符串格式化选项的 KN 库? 这是使用尖端技术支付的费用。认为我们处于 alpha 阶段,只有少数东西处于 beta 阶段。我不知道是否已经有处理字符串格式的 KN 库,但您可以开始搜索 here 和 here。您也可以加入 kotlin slack 频道并在#multiplatform 会议室中提问。 这里有官方答案,也许你也会感兴趣 是的!我见过。这也是我们发现的。该功能缺失,我们制定了解决方法。 W8ing 要添加此功能;)。顺便说一句,我已经赞成你的回答。如果您想更改已接受的答案,请随时这样做。【参考方案2】:您不能将 Kotlin 可变参数转发给 C 或 Objective-C。 C 可变参数是编译时间。 这不是 Kotlin 特定的限制。您不能通过转发所有参数从另一个可变参数 C 函数调用可变参数 C 函数。
NSString.stringWithFormat(format, args as Any)
这是不正确的。
此行采用 args
(这是一个 Array
),将其转换为 Any
并作为单个参数传递。
所以这基本上相当于
[NSString stringWithFormat:format, createKotlinArray(/* all arguments here */)]
这并不符合您的预期。
所以KT-42925 无效。 您的问题可能会通过缺少的功能之一来解决:
标准库 (KT-25506) 中的常见String.format
。但这并不容易。
支持动态构建va_list
,例如来自 Kotlin Array
(KT-42973)。在这种情况下,很容易使用这个变体:https://developer.apple.com/documentation/foundation/nsstring/1407827-initwithformat
【讨论】:
以上是关于Kotlin Native iOS 字符串格式化与可变参数的主要内容,如果未能解决你的问题,请参考以下文章
一睹为快!Kotlin 开发 iOS 的新利器:Kotlin/Native 插件
kotlin.native.concurrent.InvalidMutabilityException:在 Kotlin Multiplatform (iOS) 中使用 ktor 时冻结 <ob
Kotlin/Native 无法导入 io.ktor.network.selector.ActorSelectorManager