从字符串初始化单元

sve*_*ena 6 cocoa-touch objective-c foundation ios swift

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

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

尽管下面的解决方案有效,但如果Apple在即将到来的iOS更新中发布新的单元,则显式列出Foundation框架中预定义的所有单元将很繁琐,并且不具有隐式的前向兼容性。

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);
}
Run Code Online (Sandbox Code Playgroud)

也许我错过了SDK中一个显而易见的难题-一种识别符号而不是定义符号的初始化程序?

更新:

已确认没有Apple提供的API来执行此操作。我最终使用Objective-C运行时来查找所有继承自其名称NSDimension开头的所有类属性并对其进行迭代的类NSUnit。我映射了所有符号,类和属性名称,并可以NSUnit在运行时基于用户提供的符号创建实例。

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

以下是示例客户端代码:

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
Run Code Online (Sandbox Code Playgroud)

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

// 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]);
        // ...
    }
    // ...
}
// ...
Run Code Online (Sandbox Code Playgroud)

mat*_*att 0

没有比你正在做的更好的方法了,因为NSMeasurementFormatter仅以一种方式运行 \xe2\x80\x94 它根据测量生成字符串,而不是相反。您的方法可能存在很大缺陷,因为您没有考虑区域设置,而测量格式化程序知道如何做到这一点(针对其前进的一个方向)。如果您希望看到内置功能,您可以向 Apple 提出增强请求。

\n