• 第8条:理解“对象等同性”这一概念


    1、== 操作符

       比较的是两个指针本身,而不是其所指的对象。

    2、NSObject协议中的isEqual:方法

       一般来说两个类型不同的对象总是不相等的。如果已经知道两个对象都属于同一个类,那么就可以使用该方法了。

       例:

         - (BOOL)isEqual:(id)object {

            if (self == object) return YES;  //判断两个指针是否相等。若相等,则指向同一对象。

            if ([self class] != [object class]) return NO;  //如果不是同一类,那必然不相等。

            Person *otherPerson = (Person*)object;   //有时我们可以认为一个类对象可以和子类对象相等。所以在继承体系中,检测每个属性是否相等来判断

            if (![_firstName isEqualToString:otherPerson.firstName]) return NO;

            if (![_lastName isEqualToString:otherPerson.lastName]) return NO;

              if (_age != otherPerson.age) return NO;

            return YES;

          }     

    3、NSObject协议中的hash方法

       在编写hash方法时,应该用当前的对象做做实验,以便减少碰撞频度与降低运算复杂度之间取舍。

       在collection中,会用对象的哈希码做索引。建立哈希表。通过查找哈希表中的索引来查找元素。这样对性能消耗大。

       hash值可以自定义

          例1:-(NSUInteger)hash { return 1337; }

          例2:-(NSUInteger)hash {

                NSString *stringToHash = [NSString stringWithFormat:@"%@:%@:%i", _firstName, _lastName, _age];

                return [stringToHash hash];   //通过返回的字符串来计算hash值。 这种方法负担创建字符串的开销,比例1中返回单一值要慢。 如果添加到collection中也会产生性能问题。因为要想添加到collection中,必须先计算其哈希码。

             }

          例3:-(NSUInteger)hash {

                NSUInteger firstNameHash = [_firstName hash];

                NSUInteger lastNameHash = [_lastName hash];

                NSUInteger ageHash = [_age hash];

                 return  firstNameHash ^ lastNameHash ^ ageHash;  //这种做法既能保持较高效率,又能使生成的哈希码至少位于一定范围之内,而不会过于频繁地重复。当然,这种算法生成的哈希码还是会碰撞,不过至少可以保证哈希码有多种可能的取值。

              

    4、NSString方法中有一个特有的方法:isEqualToString:

       该方法传递的对象必须是NSString,否则结果未定义。

       这个方法比第2种方式快,第二种方法不知道对象的类型。

    5、NSArrayNSDictionary类中也具有特殊的方法

       isEqualToArray  isEqualToDictionary

       数组的检测方式:先比较两个数组的对象个数是否相等,再比较对应位置的两个对象调用其isEqual方法。 这叫做“深度等同性判定”。所以有时只需比较部分数据就可以判定二者是否等同。这是提高Hash算法的一种方式。例如:唯一标识符,在数据库中用作“主键”。

    6、自定义判定方法 (两个方法同时实现)

      如果受测对象与接收消息的对象都属于同一个类,那么就调用自己编写的判定方法,否则就交由超类来判断。

      -(BOOL)isEqualToPerson:(Person*)otherPerson {

        if (self == otherPerson) return YES;

        if (![_firstName isEqualToString:otherPerson.firstName]) return NO;

        if (![_lastName isEqualToString:otherPerson.lastName]) return NO;

        if (_age != otherPerson.age) return NO;

        return YES;

      }

        

     - (BOOL)isEqual:(id)object {

         if ([self class] = [object class]) return [self isEqualToPerson:(Person*)object];

         else return [super isEqual:object];

       }

    注意:

      第2、3种方式:如果isEqual方法判定两个对象相等,那么其hash方法必须返回同一个值;但是如果hash方法返回同一个值,isEqual方法未必会认为两者相等。也就是说两对象相等,hash值一定相等;但hash值相等,两对象未必相等。

      第4、5方式:由于OC在编译期不做强类型检查,所以容易传入类型错误的对象。开发者应该保证所传对象的类型正确。

            优点是:更容易读懂,而且不用检查两个受测对象的类型了。

    容器中可变类的等同性

       例:NSMutableSet 中,添加数据后,再改变数据,数据的哈希码变化的参照不同。所以结果难预料

       

  • 相关阅读:
    火狐浏览器修改userAgent
    清除linux缓存命令
    linux主机间复制文件
    解决两台centos虚拟机Telnet服务无法联机的问题
    Install Redis on CentOS 6.4--转
    解决 ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)异常
    主机访问虚拟机中linux上的web服务
    How can I exclude directories from grep -R?
    RPM安装命令总结--转载
    centos mongodb安装及简单实例
  • 原文地址:https://www.cnblogs.com/Pikdays/p/4117868.html
Copyright © 2020-2023  润新知