Я ударил это и работал вокруг него, используя расширение на Dictionary
для создания пользовательских индексов.
extension Dictionary {
subscript(key: String) -> Value? {
get {
let anyKey = key as! Key
if let value = self[anyKey] {
return value // 1213ns
}
if let value = self[key.lowercased() as! Key] {
return value // 2511ns
}
if let value = self[key.capitalized as! Key] {
return value // 8928ns
}
for (storedKey, storedValue) in self {
if let stringKey = storedKey as? String {
if stringKey.caseInsensitiveCompare(key) == .orderedSame {
return storedValue // 22317ns
}
}
}
return nil
}
set {
self[key] = newValue
}
}
}
Тайминги в комментариях, из сравнительного анализа различных сценариев (оптимизированная сборка, -Os
, в среднем более 1000000 итераций). Эквивалентный доступ к стандартному словарю вышел на 1257ns. Чтобы сделать две проверки эффективно удвоенной, 2412ns.
В моем конкретном случае, я видел, как заголовок возвращается с сервера, который был верблюжьим футляром или в нижнем регистре, в зависимости от сети, с которой я подключался (что-то еще для расследования). Преимущество этого в том, что, если он будет исправлен, я могу просто удалить расширение, и ничего больше не нужно изменять. Кроме того, кому-либо еще, используя код, не нужно запоминать какие-либо обходные пути - они получают этот бесплатный.
Я проверил и не видел ETag
быть модифицирована HTTPURLResponse
- если я передал ему ETag
или Etag
я получил их обратно в allHeaderFields
. В случае, если производительность является проблемой, и вы сталкиваетесь с этой проблемой, вы можете создать второй индекс, который принимает структуру Hashable
, содержащую массив. Затем передайте его в словарь, с тегами, которые вы хотите обработать.
struct DictionaryKey: Hashable {
let keys: [String]
var hashValue: Int { return 0 } // Don't care what is returned, not going to use it
}
func ==(lhs: DictionaryKey, rhs: DictionaryKey) -> Bool {
return lhs.keys == rhs.keys // Just filling expectations
}
extension Dictionary {
subscript(key: DictionaryKey) -> Value? {
get {
for string in key.keys {
if let value = self[string as! Key] {
return value
}
}
return nil
}
}
}
print("\(allHeaderFields[DictionaryKey(keys: ["ETag", "Etag"])])"
Это, как и следовало ожидать, почти эквивалентно индивидуальному поиску словарей.