String.hashValue не уникален после сброса приложения при сборке в Xcode 10 - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть код "get hash of string by String.hashValue", который я добавил ниже.Этот код хорошо работал в Xcode 9.4.1.

Хорошо работает означает, что всякий раз, когда я закрываю приложение и снова открываю его, результат hashValue остается одинаковым (уникальным)

private func cacheName(of url: String) -> String {
    // The url is url of a png image, for example www.imageurl.com/image.png
    return "\(url.hashValue)"
}

Когда я строю свой проект в Xcode 10, результат меняется каждый раз, когда я перезапускаю приложение (снова закрываю и открываю приложение).Версия iOS, устройство, версия Swift такая же.Так что я думаю, проблема в том, что Xcode 10 изменил что-то, что влияет на hashValue (может быть, настроить при сборке приложения ??)

Если я использую String.hash вместо, это работает хорошо.Но в предыдущей версии я сохранил результат hashValue, поэтому я не хочу его менять.

Как сохранить результат String.hashValue уникальным в любое время.Или любое предложение будет оценено

1 Ответ

0 голосов
/ 21 сентября 2018

В Swift 4.2 реализовано SE-0206 : Расширяемые возможности.Это вводит новую структуру Hasher, которая предоставляет случайно отобранную хеш-функцию.Вот почему результаты хеширования отличаются каждый раз (так как начальное число случайное).Вы можете найти реализацию структуры Hasher с генерацией случайного начального числа, здесь .

Если вы хотите стабильное значение хеш-функции, связанное со строкой, для всех устройств и отличий приложений,Вы можете использовать это решение от Уоррена Стрингера :

let str = "Hello"

func strHash(_ str: String) -> UInt64 {
    var result = UInt64 (5381)
    let buf = [UInt8](str.utf8)
    for b in buf {
        result = 127 * (result & 0x00ffffffffffffff) + UInt64(b)
    }
    return result
}

strHash(str)     //177798404835661

Или иметь эти пару расширений, определенных для String:

extension String {
    var djb2hash: Int {
        let unicodeScalars = self.unicodeScalars.map { $0.value }
        return unicodeScalars.reduce(5381) {
            ($0 << 5) &+ $0 &+ Int($1)
        }
    }

    var sdbmhash: Int {
        let unicodeScalars = self.unicodeScalars.map { $0.value }
        return unicodeScalars.reduce(0) {
            (Int($1) &+ ($0 << 6) &+ ($0 << 16)).addingReportingOverflow(-$0).partialValue
        }
    }
}

"Hello".djb2hash    //210676686969
"Hello".sdbmhash    //5142962386210502930

(выполняется в Xcode 10, Swift 4.2)

...