2015-08-15 2 views
1

Я пытаюсь написать метод расширения на Dictionary со следующей подписью:Swift - соответствующий класс динамически

func firstNonNilObjectForKey(keys: [Key], ofClass aClass: Any.Type = String.self) -> Value? 

Это должно помочь мне справиться с JSON словарях, где я часто нуждаются в первый непустой но иногда JSON включает в себя null как значение, которое преобразуется в NSNull в Cocoa.

Использование было бы что-то вроде:

let dict: [String:AnyObject] = [...] 
let myValue = dict.firstNonNilObjectForKey([ "key1", "key2" ]) as? String 

Вопрос в том, на реализацию - как соответствовать классу:

if let value = self[key] { 
    if value is aClass { ... } <--- error: aClass is not a type 
    if let castedValue = value as? aClass { ... } <--- error: ditto 

    let type = value.dynamicType 
    if type == aClass { ... } <--- no error, but doesn't handle subclasses! 

    // Cannot use value.isKindOfClass() since value may be Any 
} 

Я думал об альтернативе:

func firstNonNilObjectForKey<ReturnValueType>(keys: [Key]) -> ReturnValueType? 

который позволяет быть реализован как

if let value = self[key] as? ReturnValueType { ... } 

Но: - Здесь я не могу установить тип по умолчанию (мне в основном нужно String.Type). - Я не совсем уверен, как ссылаться на это:

let value = dict.firstNonNilObjectForKey([ "key1", "key2" ]) as? String <--- error: Cannot invoke 'firstNonNilObjectForKey' with an argument list of type '([String])' 
let value = dict.firstNonNilObjectForKey<String>([ ... ]) <--- error: Cannot explicitly specialize a generic function 

Я надеюсь, что это не дубликат, но большинство подобных вопросов здесь просто обращение с ситуацией, когда вы сопрягая против известного класса.

ответ

3

Я не уверен, что у меня есть требования точно, но может ли что-то подобное вам работать?

extension Dictionary { 

    func firstNonNilObjectForKey(keys: [Key]) -> String? { 
    return self.firstNonNilObjectForKey(keys, ofClass: String.self) 
    } 

    func firstNonNilObjectForKey<T>(keys: [Key], ofClass aClass: T.Type) -> T? { 
    for k in keys { 
     if let v = self[k] as? T { 
     return v 
     } 
    } 
    return nil 
    } 

} 

let dict = ["key1": 2, "key2": "Foo"] 
let aString = dict.firstNonNilObjectForKey(["key1", "key2"]) // "Foo" 
let anInt = dict.firstNonNilObjectForKey(["key1", "key2"], ofClass: Int.self) // 2 

Основной Гоча здесь является то, что я использую перегрузки в отличие от по умолчанию параметров, которые, кажется, не ладят с быстрой проверкой типов.

+0

Не будет ли первый метод в альтернативной версии рекурсивным? – jlehr

+0

@jlehr, woops, он делает. Убирай! Спасибо –

+0

Спасибо, это в значительной степени то, что мне нужно ... –

Смежные вопросы