Let’s start with a bug in a test: I was given a bug in a test that the first new order list loaded had the same data as the last one on the previous page. And it reappears a lot, so I was wondering, if it was repeated, the whole page should be repeated, why only the first one is repeated, but occasionally. I looked directly at the data returned by the backend and found that it was the backend that occasionally returned the last data on the previous page on the next page. After looking for the reason for a while, the back end said that I needed to come and go again. I am not so clear about the specific reason for the back end. Anyway, in the end, the front end is the most efficient and effective way. (I also very helpless 🤷).


When it comes to de-weighting, the first thing that comes to mind is the NSSet type, because this collection type cannot add the same data. == == == == == == == == == That is, to determine whether two Pointers point to the same object.

Some classes in Foundation, provided by the system, have their own methods for determining equality.

NSAttributedString -isEqualToAttributedString: NSData -isEqualToData: NSDate -isEqualToDate: NSDictionary -isEqualToDictionary: NSHashTable -isEqualToHashTable: NSIndexSet -isEqualToIndexSet: NSNumber -isEqualToNumber: NSOrderedSet -isEqualToOrderedSet: NSSet -isEqualToSet: NSString -isEqualToString:// NSTimeZone -isEqualToTimeZone: NSValue -isEqualToValue:Copy the code

However, for the model class that you define, how to define two objects equal. Answer first:

@interface EqualModel : NSObject
@property (nonatomic,copy)NSString *name;
@property (nonatomic,assign)NSInteger identifier;
- (BOOL)isEqualToModel:(EqualModel *)model;
@end

@implementation EqualModel
- (BOOL)isEqualToModel:(EqualModel *)model {
    if(! model) {returnNO; } BOOL haveEqualNames = (! self.name && ! model.name) || [self.name isEqualToString:model.name]; BOOL haveEqualIdentifers = self.identifier == model.identifier;return haveEqualNames && haveEqualIdentifers;
}
- (BOOL)isEqual:(id)object {
    //NSLog(@"Go isEqual");
    if (self == object) {
        return YES;
    }
    
    if(! [object isKindOfClass:[EqualModel class]]) {return NO;
    }
    
    return [self isEqualToModel:(EqualModel *)object];
}
- (NSUInteger)hash
{
    //NSLog(@"Go hash");
    return self.name.hash ^ self.identifier;
}
Copy the code

The above is the realization of Equality quoted in Mattt’s article.

You might wonder: why implement a – (NSUInteger)hash when you just implement a – (BOOL)isEqual:(id)object method? When it comes to hash values, you need to know the hash table/hash table.

Objects that inherit from NSObject have hash methods, because that method is a method declared in the

protocol. The default implementation of the hash method is to return the address of the object.

Since we don’t know why we want to implement the hash method, let’s see when the hash method is called. (We know we can’t add the same object to an NSSet class, so we’ll start with this class.)

EqualModel is defined above.

- (void)testSet
{
    NSMutableSet *set = [NSMutableSet set];
    
    EqualModel *model0 = [[EqualModel alloc]init];
    model0.name = @"model0";
    model0.identifier = 0;
    NSLog(@"-- -- -- -- -- -- -- 0 before -");
    [set addObject:model0];
    NSLog(@"-- -- -- -- -- -- -- after 0 -");
    
    EqualModel *model1 = [[EqualModel alloc]init];
    model1.name = @"model1";
    model1.identifier = 1;
    NSLog(@"-- -- -- -- -- -- -- 1 -- before");
    [set addObject:model1];
    NSLog(@"After the -- -- -- -- -- -- -- 1 --");
    
}
Copy the code

The results are as follows:

- (BOOL)isEqual:(id)object
NSSet is a hash table.
isEqual:

In addition to the addObject method (equivalent to save/write) that calls the hash method, will the fetch/read method be called? Because NSSet doesn’t have an NSDictionary-like key or array-like index to fetch an element, we’re going to put our target in containsObject, which is going to determine if there’s an element in the collection, which I think is going to pass in the element’s hash value, Find the position of the element in the hash table and see if there is a value at that position.

Check whether containsObject is called or not. The result is as follows:

isEqual

containsObject
hash
isEqual
isEqual


If the model is stored in a dictionary or used as the key of a dictionary, it will call the hash method.

  • Model is stored in the dictionary as value.
  • The result of model as a dictionary key:

    You can see that when model is used as a key, you need to follow it<NSCopying>Protocol and implementation- (id)copyWithZone:(nullable NSZone *)zoneMethod], the hash method will be called, and the key saved into the dictionary will be a copy of the model.

This time I also added many more values to the dictionary. From the running result, it can be seen that the hash method will be called when model is used as the key, but it can also be seen that the number of calls isEqual is not regular. This I really a little confused, if there is a big guy to see, know this reason, but also please don’t hesitate to give advice!! 😁 test results are shown below:

To define equality for a custom class, we need to override the isEqual and hash methods, which can be derived from xor attributes that identify instances of the type. Model’s hash method is called when a model is stored in a collection or as a dictionary key, and isEqual should be called based on the system’s underlying hash table implementation.

My ability is limited, if have understanding wrong place, also please point out, thank!!


Reference acknowledgments:

Equality in Chinese

Equality in English

Don’t tell me you really know isEqual and hash!