在Xcode 10中构建时,在重置app后,String.hashValue不是唯一的

Quo*_*yen 4 xcode ios swift xcode10

我有一个"获取字符串的哈希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)"
}
Run Code Online (Sandbox Code Playgroud)

当我在Xcode 10中构建我的项目时,每次重新启动应用程序时结果都会更改(再次关闭并打开应用程序).iOS,设备,Swift版本相同.所以我认为问题是Xcode 10已经改变了一些影响hashValue(可能在构建应用程序时配置??)

如果我使用String.hash而不是,它运作良好.但在之前的版本中,我保存了hashValue结果,因此我不想更改它.

我怎样才能String.hashValue在每次都保持独特的结果.或任何建议将不胜感激

iel*_*ani 11

Swift 4.2实施了SE-0206:Hashable Enhancements.这引入了一个新的Hasher结构,它提供了随机种子散列函数.这就是为什么散列结果每次都不同(因为种子是随机的).您可以在此处找到Hasher结构的实现,并生成随机种子.

如果你想关联到一个String稳定的哈希值,进行的跨设备和应用lauches,你可以使用这个解决方案沃伦·斯金格:

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

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

(这是在Xcode 10,Swift 4.2上执行的)

  • @ielyamani 谢谢你!现在可以工作了!这么巧合,我测试的第一根弦就失败了,哈哈 (2认同)