从字符串初始化单元 [英] Initializing a Unit from String

查看:81
本文介绍了从字符串初始化单元的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种 Unit(symbol:String)类型的初始化程序,该初始化程序可以识别,而不是定义符号。

I'm looking for a Unit(symbol: String) kind of initializer that would recognize, not define a symbol.

下面是一个代码段,通过提供有限的解决方案来说明我的问题。

Here's a code snippet to illustrate my problem by providing a limited solution to it.

尽管下面的解决方案可行,但是如果Apple在即将到来的iOS更新中发布新的单元,则显式列出 Foundation框架中预定义的所有单元是乏味的,并且没有隐含的向前兼容性。

Although the solution below works, explicitly listing all units predefined in the Foundation framework is tedious and does not have implicit forward compatibility should Apple release new units in upcoming iOS updates.

func matchedUnit<S: Sequence>(symbol: String, valid sequence: S) -> S.Iterator.Element? where S.Iterator.Element: Unit {
    let symbols = sequence.map { $0.symbol };
    let candidate = zip(sequence, symbols).first {
        return $0.1 == symbol;
        }?.0
    return candidate;
}

let knownUnitsOfLength = [UnitLength.meters, UnitLength.centimeters, UnitLength.kilometers, UnitLength.decimeters];

if let aUnit = matchedUnit(symbol: "dm", valid: knownUnitsOfLength) {
    let measurement = Measurement(value: 1, unit: aUnit);
}

也许我错过了SDK中一个显而易见的难题-

Perhaps I'm missing an obvious piece of the puzzle in the SDK - an initializer that recognizes a symbol rather than defines one?

更新:

可以识别符号而不是定义符号的初始值设定项吗?已确认没有Apple提供的API来执行此操作。我最终使用 Objective-C运行时查找了所有从 NSDimension 继承的类,并遍历了所有以<$ c开头的类属性。 $ c> NSUnit 的名称。我映射了所有符号,类和属性名称,并可以在运行时基于用户提供的符号创建 NSUnit 实例。

It has been confirmed that there is no Apple provided API to do that. I ended up using Objective-C runtime to find all classes that inherit from NSDimension and iterate over all of their class properties that begin with NSUnit in their names. I mapped all the symbols, class and property names and can create NSUnit instance at runtime based on a user provided symbol.

在语言支持方面,它与 NSMeasurementFormatter 的级别不同。 但是我会自动访问Apple在以后版本中引入的任何新单位和符号。

Granted, it is not at the same level with NSMeasurementFormatter when it comes to language support. BUT I automatically gain access to any new units and symbols that are introduced by Apple with future releases.

下面是一个示例客户端代码:

Below is a sample client code:

NSUnit *kg = [NSUnit unitRecognizingSymbol:@"kg"];
NSMeasurement *mkg = [[NSMeasurement alloc] initWithDoubleValue:3.0 unit:kg];

NSUnit *g = [NSUnit unitRecognizingSymbol:@"g"];
NSMeasurement *mg = [[NSMeasurement alloc] initWithDoubleValue:200 unit:g];

NSMeasurement *total = [mkg measurementByAddingMeasurement:mg];

NSMeasurementFormatter *formatter = [[NSMeasurementFormatter alloc] init];
[formatter setUnitOptions:NSMeasurementFormatterUnitOptionsProvidedUnit];

NSLog(@"%@", [formatter stringFromMeasurement:total]);
// 3.2 kg

这是实现方面的核心部分。

And here's what the core part of the implementation side looks like.

// Count receives its value from objc_copyClassList().
unsigned int classCount;
Class *classes = objc_copyClassList(&classCount);
// Inspect all available classes.
for (int classIterator = 0; classIterator < classCount; classIterator++) {
    char const *className = class_getName(classes[classIterator]);

    // Classes we are looking for are derived from NSDimension or NSUnit.
    Class superClass = class_getSuperclass(classes[classIterator]);
    char const *superClassName = class_getName(superClass);

    // Single out NSDimension exception because NSDimension itself inherits from NSUnit.
    if ((strcmp(superClassName, "NSDimension") == 0 || strcmp(superClassName, "NSUnit") == 0) && strcmp(className, "NSDimension") != 0) {
        // To access available class properties, gain access to meta class.
        Class meta = objc_getMetaClass(class_getName(classes[classIterator]));

        // Count receives its value from class_copyPropertyList()
        unsigned int propertyCount = 0;
        objc_property_t *properties = class_copyPropertyList(meta, &propertyCount);
        // Inspect all available class properties.
        for (int propertyIterator = 0; propertyIterator < propertyCount; propertyIterator++) {
            char const *propertyName = property_getName(properties[propertyIterator]);
        // ...
    }
    // ...
}
// ...


推荐答案

没有比您正在做的更好的方法了,因为 NSMeasurementFormatter 只能以一种方式运行-它是通过​​度量生成字符串,而不能以其他方式运行。您的方法可能存在很大缺陷,因为您没有考虑语言环境,而度量格式化程序会知道该语言环境(针对该语言环境的一个方向)。如果您希望内置此功能,可以向Apple提出增强请求。

There's no better way than what you're doing, because NSMeasurementFormatter only runs one way — it makes a string from a measurement, not the other way around. Your approach is likely to be highly flawed because you are not taking account of locale, which a measurement formatter knows how to do (for the one direction in which it goes). You could file an enhancement request with Apple if this is something you'd like to see built in.

这篇关于从字符串初始化单元的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆