我在尋找Unit(symbol: String)
類型的初始化程序,它會識別,未定義符號。從字符串初始化單元
下面是一個代碼片段,通過向其提供有限解決方案來說明我的問題。
雖然下面的工作方案,明確列出在Foundation框架預定義了所有單位是乏味的,沒有隱含的向前兼容性應該在蘋果的iOS即將更新推出新單位。
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中一個明顯的難題 - 識別符號而不是定義一個符號的初始化工具?
UPDATE:
已經證實,有沒有蘋果提供的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
而且這裏是實施方的核心部分是什麼樣子。
// 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]);
// ...
}
// ...
}
// ...