Kotlin Native iOS string formatting with vararg

隐身守侯 提交于 2021-02-08 04:59:50

问题


Based on this issue about using NSString formatting I try to implement multiplatform implementation for formatting when using vararg, with no luck so far.

What I did

  • added 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;
}
  • compiled it in 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 {
                }
            }
        }
    }
  • Created StringExtensions.kt in commonMain
expect class StringType

expect fun String.format(format: String, vararg args: Any?): StringType?
  • in 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)
}
  • example
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)
  • output - as you see no values substitutions occured for some reason
http://geomag.bgs.ac.uk/web_service/GMModels/igrf/13/?latitude=0.000000&longitude=0.000000&altitude=0&date=43344272-198763328-00&format=json

Edit

stringWithFormat gives the same result

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

Edit 2

Created issue https://youtrack.jetbrains.com/issue/KT-42925


回答1:


I confirm what you say about NSString.stringWithFormat. The feature is missing as we read in the JB offical answer from Svyatoslav Scherbina and we could follow the issue from you here: KT-42925

As an awful workaround, I was suggesting something like that (WARNING: not exhaustive, without many index count checks...)

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
}

But look if it could be a valid workaround for you.




回答2:


You can't forward Kotlin variadic arguments to C or Objective-C. C variadics are compile time. It is not a Kotlin-specific limitation. You can't call a variadic C function from another variadic C function with forwarding all the arguments.

NSString.stringWithFormat(format, args as Any)

This is not correct. This line takes args (which is an Array), casts it to Any and passes as a single argument.

So this is mostly equivalent to something like

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

which doesn't do what you expect.

So KT-42925 is not valid. Your problem could possibly be solved by one of the missing features:

  • Common String.format in stdlib (KT-25506). But this is not easy.
  • Support for building va_list dynamically, e.g. from Kotlin Array (KT-42973). In this case it would be easy to use this variant: https://developer.apple.com/documentation/foundation/nsstring/1407827-initwithformat


来源:https://stackoverflow.com/questions/64495182/kotlin-native-ios-string-formatting-with-vararg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!