mickeysox
mickeysox

Reputation: 311

What is the different between these structs identifiers

The below 2 structs are the same with the exception of how they generate the identifier. Could you please explain what the difference is? If I use the first, my UICollectionViewDiffableDataSource works as expected (no scrolling on update). If I use the second, the diffable will scroll.

struct PostDetail {
    var comment: Comment
    var like: CommentLike?
    var user: User

}

extension PostDetail: Hashable {
    var identifier: UUID {
       return UUID()
    }
    
    func hash(into hasher: inout Hasher) {
        return hasher.combine(identifier)
    }
    
    public static func == (lhs: PostDetail, rhs: PostDetail) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

struct PostDetail {
    let identifier = UUID()
    var comment: Comment
    var like: CommentLike?
    var user: User

}

extension PostDetail: Hashable {
    
    func hash(into hasher: inout Hasher) {
        return hasher.combine(identifier)
    }
    
    public static func == (lhs: PostDetail, rhs: PostDetail) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

Upvotes: 0

Views: 74

Answers (2)

matt
matt

Reputation: 535304

Just to expand on what I've said in my comment and Rob Napier has said in his answer:

In your first struct, identifier is merely a function that generates a totally new value every time it is called. So it is never the same twice! Let's try it. Here's a reduced version of your struct:

struct PostDetail : Equatable {
    var identifier: UUID {
        return UUID()
    }
    static func ==(lhs:PostDetail, rhs:PostDetail) -> Bool {
        lhs.identifier == rhs.identifier
    }
}

Let's test it:

let p = PostDetail()
p.identifier // 3FFE9C66-5B80-4EF4-95EC-50388D35040B
p.identifier // 2D180097-CFAC-47E9-8530-C3BD3D39F433

So its "identifier" is not a constant; just the opposite, it is constantly changing. But you can't "identify" anything that way. Any attempt at defining Equatable based on that will fail, because no two PostDetail objects can ever be equal, even if they are the same object!

let p2 = PostDetail()
p2 == p2 // false

Similarly your Hashable will always fail, in the sense that no two PostDetail objects will fall into the same hash bucket, not even two instances of the same object.

To be an identifier, a UUID must be constant. In your second struct, we see this line:

let identifier = UUID()

That is a constant. It is generated when the instance is created and it never changes (because let). That is how a UUID needs to behave.

So, you may seem to be working around some sort of animation "glitch", but you are doing so in a totally illegal and nonsensical way. There is no animation, I presume, because every PostDetail is "different" from every other, including itself. The entire diffable datasource content is being replaced, so there is nothing to animate (or something like that). You may be avoiding some interface behavior you don't like, but you are just fooling yourself, like someone who puts black tape over a car dashboard warning light.

Upvotes: 1

Rob Napier
Rob Napier

Reputation: 299345

The code in the first example is almost certainly wrong:

var identifier: UUID {
   return UUID()
}

This creates a new identifier every time you access it, which is the opposite of "an identifier." The second example is correct.

Upvotes: 1

Related Questions