【Swift 4.2】 【Swift 5】 Hashable과 Codable과 상속을 동시에 사용하면 hashValue의 참조로 충돌한다

【개요】



Swift 4.2/5.0에서 Hashable과 Codable과 상속을 동시에 사용하면 hashValue 참조로 충돌합니다.

【환경】



let lang = "Swift 4.2"+ "Swift 5.0"
let env="XCode10"+ "XCode10.2"

【상세 내용】



먼저 Swift 4.2에서 도입된 func hash(into hasher: inout Hasher)를 사용하여 Hashable을 구현합니다.
ただし、下記のクラスはテストファイル中ではなく、アプリ内のファイル(アプリバンドルない)に記述します。(2019/3/30更新)

open class HashableTestModel: Hashable
{
    public var uniqueIdentifier: String

    public init()
    {
        self.uniqueIdentifier = String(arc4random())
    }

    // Equatable
    static public func ==(lhs: HashableTestModel, rhs: HashableTestModel) -> Bool
    {
        return true
    }

    public func hash(into hasher: inout Hasher)
    {
        hasher.combine(uniqueIdentifier)
    }
}




↑ 여기까지는 문제 없습니다. 그런 다음 HashableTestModel을 Codable로 설정합니다.
open class HashableTestModel: Hashable, Codable
{

또한 HashableTestModel을 상속한 HashableTestModelChild를 만듭니다.
HashableTestModelChild는 공백으로 남을 수 있습니다.

open class HashableTestModelChild: HashableTestModel
{

}


이제 테스트합니다.
    func testCoreModelHashable() {

        let val = HashableTestModel()
        print(val.hashValue)
    }



충돌합니다.
Codable을 중지하거나 상속을 중지하면 작동합니다.
또 문제가 되고 있는 클래스를 테스트 파일내에 기술하면 동작합니다.
신기하네요.

일반적으로 두 코드 모두 앱의 메인 번들에 작성되어야하므로 문제가 발생하지 않습니다. 테스트에서는 죽지만.

문제는 Embedded Framework를 사용하고 호출자와 해당 클래스의 번들이 다른 경우입니다. (실제 내 테스트에서 메인 번들에서 Embedded Framework 위의 클래스를 호출하는 것처럼 충돌했습니다.

【더 알게 된 것】



베이스 클래스를, 다른 번들(Embedded Framework내 등)에 두고,
상속 클래스를 메인 번들에 넣은 상태에서 인스턴스를 만들고 print(val.hashValue)를 실행하면 충돌하지 않습니다.
open class HashableTestModelChild: HashableTestModel만들 때 기본 클래스
    public func hash(into hasher: inout Hasher)
    {
        hasher.combine(uniqueIdentifier)
    }

불리지 않습니다.

【샘플 코드】



샘플 코드는 여기에 넣었습니다.

6월에 WWDC에 가서 애플의 엔지니어에게 직접 들어보자고 생각합니다.

【해결했습니다】



open class HashableTestModel_Other: Codable
{
    public var uniqueIdentifier: String

    public init()
    {
        self.uniqueIdentifier = String(arc4random())
    }

    // Equatable
    static public func ==(lhs: HashableTestModel_Other, rhs: HashableTestModel_Other) -> Bool
    {
        return true
    }
}

extension HashableTestModel_Other: Hashable
{
    public func hash(into hasher: inout Hasher)
    {
        hasher.combine(uniqueIdentifier)
    }
}

open class HashableTestModelChild_Other: HashableTestModel_Other
{

}


이와 같이, Hashable을 extension으로 기술하면 크래시하지 않는 것을 알았습니다.

좋은 웹페이지 즐겨찾기