Swift的hashValue导致应用程序崩溃

13

由于某种原因,在实现对象的hashValue以便在其他结构中使用时,程序崩溃。当我尝试获取任何字符串对象的hashCode时,它似乎会崩溃。它正在扩展一个结构,但是在使用hashValue时,所访问的字段已经被定义。我通过测试诸如"TEST"之类的字符串来验证了这一点,但它仍然会崩溃。像id字段这样的整数hashValues没问题。任何帮助将不胜感激。

Swift 1.2 Xcode 6.4

extension SwiftObject:Hashable{//Hashable inherits Equatable and used for sets
    var hashValue: Int {
        let prime:Int = 31;
        var result:Int = 17;
        result = prime * result + id.hashValue
        result = prime * result + name.hashValue
        var locationString:String = "\(location.latitude.hashValue), \(location.longitude.hashValue)"
        result = prime * result + locationString.hashValue
        return result
    }
}

func == (lhs: Object, rhs: Object) -> Bool {
    let primaryBool:Bool = lhs.id == rhs.id
    let secondaryBool:Bool = lhs.name == rhs.name
    let thirdBool:Bool = lhs.location.distance(rhs.location) == 0
    return primaryBool || (secondaryBool && thirdBool)
}

堆栈跟踪:

* thread #1: tid = 0x6c2b4, 0x000000010f021af3 IphoneApplication`IphoneApplication.AppStruct.hashValue.getter : Swift.Int(self=IphoneApplication.AppStruct at 0x00007fff50befde8) + 2771 at IphoneApplication.swift:96, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
  * frame #0: 0x000000010f021af3 IphoneApplication`IphoneApplication.AppStruct.hashValue.getter : Swift.Int(self=IphoneApplication.AppStruct at 0x00007fff50befde8) + 2771 at IphoneApplication.swift:96
    frame #1: 0x000000010f02302b IphoneApplication`protocol witness for Swift.Hashable.hashValue.getter : Swift.Int in conformance IphoneApplication.AppStruct : Swift.Hashable in IphoneApplication + 651 at IphoneApplication.swift:88
    frame #2: 0x0000000111fc1aad libswiftCore.dylib`Swift._NativeSetStorage._bucket <A : Swift.Hashable>(Swift._NativeSetStorage<A>)(A) -> Swift.Int + 29
    frame #3: 0x0000000111fd071e libswiftCore.dylib`Swift._VariantSetStorage.nativeUpdateValue <A : Swift.Hashable>(inout Swift._VariantSetStorage<A>)(A, forKey : A) -> Swift.Optional<A> + 334
    frame #4: 0x0000000111fbb344 libswiftCore.dylib`Swift._VariantSetStorage.updateValue <A : Swift.Hashable>(inout Swift._VariantSetStorage<A>)(A, forKey : A) -> Swift.Optional<A> + 52
    frame #5: 0x0000000111fbb2c0 libswiftCore.dylib`Swift.Set.insert <A : Swift.Hashable>(inout Swift.Set<A>)(A) -> () + 144
    frame #6: 0x000000010f032592 IphoneApplication`IphoneApplication.FoursquarePlacesService.(result=0x00007fcfc87700d0, self=0x00007fcfca825c90) -> (IphoneApplication.WOMapUI, searchTerm : Swift.String) -> Swift.Set<IphoneApplication.AppStruct>).(closure #1) + 8162 at FoursquarePlacesService.swift:102
    frame #7: 0x000000010f032917 IphoneApplication`reabstraction thunk helper from @callee_owned (@owned QuadratTouch.Result) -> (@unowned ()) to @callee_owned (@in (result : QuadratTouch.Result)) -> (@out ()) + 23 at FoursquarePlacesService.swift:0
    frame #8: 0x000000010f02d171 IphoneApplication`partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned QuadratTouch.Result) -> (@unowned ()) to @callee_owned (@in (result : QuadratTouch.Result)) -> (@out ()) + 81 at FoursquarePlacesService.swift:0
    frame #9: 0x0000000111e19150 QuadratTouch`reabstraction thunk helper from @callee_owned (@in (result : QuadratTouch.Result)) -> (@out ()) to @callee_owned (@owned QuadratTouch.Result) -> (@unowned ()) + 32 at Task.swift:0
    frame #10: 0x0000000111e190f8 QuadratTouch`QuadratTouch.DataTask.(self=0x00007fcfcd004100, result=0x00007fcfc87700d0) -> () -> ()).(closure #1).(closure #1) + 232 at Task.swift:71
    frame #11: 0x0000000111e19187 QuadratTouch`reabstraction thunk helper from @callee_owned () -> (@unowned ()) to @callee_unowned @objc_block () -> (@unowned ()) + 39 at Task.swift:0
    frame #12: 0x00000001100a757f Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
    frame #13: 0x000000010ffe80b2 Foundation`-[NSBlockOperation main] + 98
    frame #14: 0x000000010ffca774 Foundation`-[__NSOperationInternal _start:] + 645
    frame #15: 0x000000010ffca383 Foundation`__NSOQSchedule_f + 184
    frame #16: 0x0000000112e60614 libdispatch.dylib`_dispatch_client_callout + 8
    frame #17: 0x0000000112e48a1c libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1664
    frame #18: 0x000000010f8841f9 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    frame #19: 0x000000010f845dcb CoreFoundation`__CFRunLoopRun + 2043
    frame #20: 0x000000010f845366 CoreFoundation`CFRunLoopRunSpecific + 470
    frame #21: 0x0000000113d02a3e GraphicsServices`GSEventRunModal + 161
    frame #22: 0x00000001109288c0 UIKit`UIApplicationMain + 1282
    frame #23: 0x000000010f027727 IphoneApplication`main + 135 at AppDelegate.swift:13
    frame #24: 0x0000000112e94145 libdyld.dylib`start + 1

请您能够贴出堆栈跟踪吗? - fumoboy007
此外,在定义这些变量时,您不需要指定类型,因为Swift将从您分配给变量的值中推断出类型。 - fumoboy007
我开始相信这是整数溢出的问题。 - kdgwill
1个回答

21

更新(Swift 4.2+)

如果由于某些原因确实需要手动实现Hashable遵从协议,请升级到Swift 4.2+以采用新的Hashable协议,该协议为您提供了一个易于使用的Hasher对象,其内部使用了一个设计良好的哈希算法。

例如,上述哈希函数将被转换为

func hash(into hasher: inout Hasher) {
   hasher.combine(id)
   hasher.combine(name)
   hasher.combine(location)
}

更新(Swift 4.1+)

升级到Swift 4.1以获得编译器支持的自动合成HashableEquatable符合性!有关详细信息,请参见Swift Evolution proposal


原始回答

是的,看起来像是整数溢出。您可以尝试使用乘法和加法运算符的溢出版本:&*&+

The Swift Programming Language book中阅读更多内容。


1
这完美地解决了问题,谢谢你提供的修复和链接。 - kdgwill
@kdgwill 不客气! - fumoboy007
在这里调用 combine 是错误的。请调用 hash(into:)。请参阅相关的 WWDC 2018 视频。 - matt
是的,但视频对此非常明确。我倾向于相信视频。 - matt
2
Swift文档和WWDC会议都是正确的。hasher.combine(foo)foo.hash(into: &hasher)是完全等价的;请随意使用您喜欢的任何一种形式。 - Karoy Lorentey
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接