# Using Identifiable in SwiftUI

In this blog post I will explain `Identifiable` and `ObjectIdentifier `based on the example of using SwiftUI's [`List`](https://developer.apple.com/documentation/SwiftUI/List).

Typically you create lists dynamically from an underlying collection of data.

```Swift
struct Ocean {
    let name: String
}

struct ContentView: View {
    private var oceans = [
        Ocean(name: "Pacific"),
        Ocean(name: "Atlantic"),
        Ocean(name: "Indian"),
        Ocean(name: "Southern"),
        Ocean(name: "Arctic")
    ]
    
    var body: some View {
        List(oceans) {
            Text($0.name)
        }
    }
}
```

This will fail

> Initializer 'init(_:rowContent:)' requires that 'Ocean' conform to 'Identifiable'.

SwiftUI needs to know how it can identify each item uniquely otherwise it will struggle to compare view hierarchies to figure out what has changed.

There are several possible solutions.

# Using a different initializer 

```Swift
    var body: some View {
        List(oceans, id: \.name) {
            Text($0.name)
        }
    }
```

Here we use an initializer to pass in the key path of an attribute that helps SwiftUI to identify each item uniquely.

Choose this option if you want to keep your data model unchanged.

# Adopting Identifiable

```Swift
struct Ocean: Identifiable {
    let name: String
    let id = UUID()
}
```

This is my recommended way of dealing with this situation.

As you can see it is quite simple. Swift 5.1 added the [`Identifiable`](https://developer.apple.com/documentation/swift/identifiable) protocol to the standard library, declared as follows:

```Swift
protocol Identifiable {
    associatedtype ID: Hashable
    var id: ID { get }
}
```

The only requirement is to have a property with the name `id` which is `Hashable`.

> Use the `Identifiable` protocol to provide a stable notion of identity to a class or value type. For example, you could define a User type with an id property that is stable across your app and your app’s database storage. You could use the id property to identify a particular user even if other data fields change, such as the user’s name.

An excellent article to dig deeper is:

%[https://nshipster.com/identifiable/]

> In Swift, only class instances and metatypes have unique identities. There is no notion of identity for structs, enums, functions, or tuples.

# Using a Reference Type For Implicit Adoption

`Identifiable` provides a default implementation for class types (using [`ObjectIdentifier`](https://developer.apple.com/documentation/swift/objectidentifier)), which is only guaranteed to remain unique for the lifetime of an object.

```Swift
class Ocean: Identifiable {
    let name: String

    init(name: String) {
        self.name = name
    }
}
```

This works because of the default protocol implementation of `id` for `AnyObject` types:

```Swift
extension Identifiable where Self: AnyObject {
  public var id: ObjectIdentifier {
    return ObjectIdentifier(self)
  }
}
```

If an object has a stronger notion of identity, it may be appropriate to provide a custom implementation.

Note that for a class type an explicit initializer is needed. Otherwise, you will encounter the error:

> 'Ocean' cannot be constructed because it has no accessible initializers

If you wanna learn more about `ObjectIdentifier` then I recommend this article:

%[https://swiftrocks.com/understanding-swifts-objectidentifier]
