Search code examples
iosobjective-chashnsobject

OC ,any Instance objects's hash will change after init?


1.every object has only hash, not equal other object?

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
obj1.hash != obj2.hash

object'hash base on what?

2.object's hash never change when I change object's properties???

or

(object init after object's hash can't change ???)

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
NSObject *obj3 = [[NSObject alloc] init];
NSDictionary *dic = @{@(obj1.hash):obj1,@(obj2.hash):obj2,@(obj3.hash):obj3,...};

I don't know the above two questions, so I'm not sure that I write is correct.

other(English is not my native language,grammar mistake forgive me)


Solution

  • As @Sulthan says, the default implementation of hash is the address of object.

    In your subclass, you can override -hash method, you may calculate the hash according to your properties, if so, when you change the property, the hash will change.

    For example: NSMutableString, you can check the log to see the result, when you change the content of NSMutableString, its hash changed.

    NSMutableString *s = [[NSMutableString alloc] initWithString:@"124"];
    NSLog(@"%@", @([s hash]));
    [s appendString:@"123"];
    NSLog(@"%@", @([s hash]));
    

    When you override hash method and add the instance of that class into a collection which use object's hash to locate object, you must make sure the hash function never change.

    In Apple's documentation, it talks about the hash method in NSObject protocol :

    If two objects are equal (as determined by the isEqual: method), they must have the same hash value. This last point is particularly important if you define hash in a subclass and intend to put instances of that subclass into a collection. If a mutable object is added to a collection that uses hash values to determine the object’s position in the collection, the value returned by the hash method of the object must not change while the object is in the collection. Therefore, either the hash method must not rely on any of the object’s internal state information or you must make sure the object’s internal state information does not change while the object is in the collection. Thus, for example, a mutable dictionary can be put in a hash table but you must not change it while it is in there. (Note that it can be difficult to know whether or not a given object is in a collection.)

    Here is an example:

    @interface Object : NSObject
    @property (nonatomic) NSInteger ttt;
    @end
    
    @implementation Object
    
    - (NSUInteger)hash {
        return _ttt;
    }
    
    @end
    
    NSMutableSet *set = [NSMutableSet set];
    Object *obj = [[Object alloc] init];
    obj.ttt = 10;
    [set addObject:obj];
    obj.ttt = 9;
    [set addObject:obj];
    NSLog(@"%@", @(set.count));
    

    The result is 2 even the obj is the same object. The reason is that NSMutableSet use hash to determine if there already exists a object in the set. You can imagine there is a simple hash table, obj locates at 10 when it is first inserted into the set. Then you change ttt property to 9, its hash changed, NSMutableSet finds the position at 9 is empty, so it inserted the object again at 9.