# IGListDiffable and Equality

This guide details how to write good `isEqual:` methods.

## Background

`IGListKit` requires that models implement the method `isEqualToDiffableObject:` which should perform the same type of check as `isEqual:`, but without impacting performance characteristics like in Objective-C containers such as `NSDictionary` and `NSSet`.

## `IGListDiffable` bare minimum

The quickest way to get started with diffable models is use the object itself as the identifier, and use the superclass’s `-[NSObject isEqual:]` implementation for equality:

    - (id<NSObject>)diffIdentifier {
      return self;
    }

    - (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object {
      return [self isEqual:object];
    }

## Writing better Equality methods

Even though `IGListKit` uses the method `isEqualToDiffableObject:`, the concepts of writing a good equality check apply in general. Here are the basics to writing good `-isEqual:` and `-hash` functions. Note this is all Objective-C but applies to Swift also.

- If you override `-isEqual:` you must override `-hash`. Check out this article by Mike Ash for details.
- Always compare the pointer first. This saves a lot of wasteful `objc_msgSend(...)` calls and value comparisons if checking the same instance.
- When comparing object values, always check for `nil` before `-isEqual:`. For example, `[nil isEqual:nil]` unintuitively returns `NO`. Instead, do `left == right || [left isEqual:right]`.
- Always compare the cheapest values first. For example, doing `[self.array isEqual:other.array] && self.intVal == other.array` is extremely wasteful if the `intVal` values are different. Use lazy evaluation!

As an example, if I had a `User` model with the following interface:

    @interface User : NSObject

    @property NSInteger identifier;
    @property NSString *name;
    @property NSArray *posts;

    @end

You would implement its equality methods like so:

    @implementation User

    - (NSUInteger)hash {
      return self.identifier;
    }

    - (BOOL)isEqual:(id)object {
      if (self == object) {
          return YES;
      }

      if (![object isKindOfClass:[User class]]) {
          return NO;
      }

      User *right = object;
      return self.identifier == right.identifier
          && (self.name == right.name || [self.name isEqual:right.name])
          && (self.posts == right.posts || [self.posts isEqualToArray:right.posts]);
    }

    @end

## Using both `IGListDiffable` and `-isEqual:`

Making your objects work universally with Objective-C containers and `IGListKit` is easy once you’ve implemented `isEqual:` and `-hash`.

    @interface User <IGListDiffable>

    // properties...

    @end

    @implementation User

    - (id<NSObject>)diffIdentifier {
        return @(self.identifier);
    }

    - (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object {
        return [self isEqual:object];
    }

    @end

© 2017 Instagram. All rights reserved. (Last updated: 2017-01-04)

Generated by jazzy ♪♫ v0.7.3, a Realm project.