无论我们使用什么语言,总是会出现需要判断两个对象是否相等的情况,OC当然也不例外。首先看一段代码:

        NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding];
NSString *str2 = @"equal";
if(str1 == str2)
{
NSLog(@"equal");
}

很明显,在我们开来,str1和str2是“相等的”。但是事实上equal是不会被打印的。这是因为如果我们直接比较两个对象是否相等,实际上比较的是两个对象的指针是否相等。

上述代码中str1和str2是分别指向两块不同的内存的,所以肯定不会像等了。

我们稍微修改一下代码再看看:

        NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding];
NSString *str2 = @"equal";
if([str1 isEqual:str2])
{
NSLog(@"equal");
}

注意看加粗语句,我们改用NSObject提供的isEqual方法比较,发现"equal"被打印了出来。因为isEqual在NSString 内部被实现的时候比较的是真正的字符串是否相等!

对象等同性实现

看过上面例子后,现在我们自己创建一个类来进一步说明等同性

#import <Foundation/Foundation.h>

@interface EqualObject : NSObject

@property(nonatomic ,strong)NSString *name;

@end

#import "EqualObject.h"

@implementation EqualObject

@end

定义了一个EqualObject类,有一个name属性。

现在我们创建两个对象来比较一下:

 EqualObject *object1 = [EqualObject new];
EqualObject *object2 = [EqualObject new]; if([object1 isEqual:object2])
{
NSLog(@"equal");
}

发现代码运行结束并没有输出"equal",原因就在于isEqual方法是需要我们自己实现的。NSObject的isEqual:方法默认是比较两个对象指向的地址是否相等,这里开辟了两个对象肯定不想等了。

现在我们添加isEqual:方法的实现:

-(BOOL)isEqual:(id)object
{
if([self class] == [object class])
{
if(![self.name isEqual:[(EqualObject *)object name]])
{
return NO;
}
return YES;
}
else
{
return [super isEqual:object];
}
}

这里稍微解释一下,为什么两个对象不同类就调用父类的isEqual:这是因为,有的时候我们是可以让子类等于父类的,我们只需要关注属性是否相同时可以这样写,如果不需要也可以不在父类处理那么久默认不相等了。

现在我们不对name进行赋值操作依然是没有值打印出来的。

修改客户端代码:

        EqualObject *object1 = [EqualObject new];
EqualObject *object2 = [EqualObject new];
object1.name = @"xiaoming";
object2.name = @"xiaoming"; if([object1 isEqual:object2])
{
NSLog(@"equal");
}

发现这时候在运行就已经相等了。

为类定制等同性方法

我们可以看到NSString除了可以用isEqual比较是否相等意外,还可以使用isEqualToString来比较!这是专为NSString类定制的等同性方法,提供这样的方法就可以很明确我们实现了该对象的isEqual方法。

下面为EqualObject提供定制的等同性方法,并修改isEqual:方法

- (BOOL)isEqualToEqualObject:(EqualObject *)object
{
if(self == object)
return YES;
if(![self.name isEqualToString:object.name])
return NO;
return YES;
} - (BOOL)isEqual:(id)object
{
if([self class] == [object class])
{
return [self isEqualToEqualObject:object];
}
else
{
return [super isEqual:object];
}
}

然后客户端修改

        if([object1 isEqualToEqualObject:object2])
{
NSLog(@"equal");
}

很顺利的"equal"了...

对象hash码

每一个OC对象内部都是有一个hash码的,当对象存入集合中(Array,Set,HashTable等),那么他们的hash码会被当做键来决定他们该放入哪一个集合中。

首先我们先看一下集合内部是如何存储的

hashCode subCollection
code1 value1,value2,value3,value4
code2 value5,value6
code3 value7
code4 value8,value9,value10

集合的内部并不像我们所想的那样,是一个hash表,它将插入的对象根据hashCode来决定放入哪一个子集合。如果要删除或者比较集合内元素,它首先根据hashCode找到子集合,然后跟子集合的每个元素比较。

所以如果我们的对象的hashCode如果都相同,那么就会出现严重的效率问题,

理论上来说,我们确定等同性的两个对象的hash应该是相同的而不等的两个对象hash也应该不等,这样在存入hashTable之类的集合时,就 会避免相同对象的重复添加,比如我们两个对象hash相等,但实际对象不等,那么添加的时候就会被添加到同一subCollection下面。

所以为了避免这种情况,我们尽量自己实现一种避免重复的方式,

这里提供一种,添加一个新属性age,hash实现如下:

- (NSUInteger)hash
{
NSUInteger nameHash = [_name hash];
NSUInteger ageHash = _age;
return nameHash ^ ageHash;
}

集合中的对象等同性

我们对NSArray调用isEqual方法,它会对集合里的每个对象和另一个集合相同位置的对象进行isEqual:操作,只有全部相等,两个集合才相等。

这里说一下,集合里面最后添加都是不可变元素,如果是可变性元素会出现不法控制的情况。

比如我们往NSSet里面添加两个NSMutableArray,一开始两个array不等,那么set中就有两个元素。

然后修改一个array使两个相等,这是set中就会有两个相等的元素存在!

Objective-C——判断对象等同性的更多相关文章

  1. Effective Objective-C 2.0 — 第8条:理解“对象等同性”这一概念

    第8条:理解“对象等同性”这一概念 若想检测对象的等同性,请提供“isEqual”与 hash 方法 相同的对象必须具有相同哈希码,但是两个哈希码相同的对象却未必相同. 不要盲目地逐个检测每条属性,而 ...

  2. 如何理解iOS的“对象等同性”

    在iOS开发过程中,我们经常需要用到等同性来判断两个对象是否相等,通常我们会使用==来判断,但是这样比较出来的结果可能不是我们期望的:所以,一般我们会使用NSObject协议声明的isEqual方法来 ...

  3. 深入Java虚拟机--判断对象存活状态

    程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的.这个三个部分的特点 ...

  4. js中判断对象具体类型

    大家可能知道js中判断对象类型可以用typeof来判断.看下面的情况 <script> alert(typeof 1);//number alert(typeof "2" ...

  5. java虚拟机判断对象是否存活的方式

    引用计数算法:   给对象添加一个引用计数器,每当有地方应用时,计数器值就加一,当引用失效时,程序计数器就减一,只要引用计数器的值为零时,就表示对象不可能再被引用,例如微软的 component ob ...

  6. 将对象的所有属性名放到一个数组中 || 获得对象的所有属性名 || return;不具有原子性 || 怎样自己制作异常|| 判断对象有没有某个属性 || 当传递的参数比需要的参数少的时候,没有的值会被赋予undefined || 获得函数实际传递的参数 || 怎么用函数处理一个对象 || 用一个名字空间定义一个模块所有的函数 || 给一个对象添加方法

    获得对象的所有属性名 || 将对象o的所有属性名放到数组中 var o = {x:1,y:2,z:3}; var arr = []; var i = 0; for(arr[i++] in o){};/ ...

  7. JavaScript中判断对象类型方法大全1

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  8. freemarker判断对象是否为空

    freemarker中显示某对象使用 ${name}.   但如果name为null,freemarker就会报错.如果需要判断对象是否为空: <#if name??> …… </# ...

  9. 关于jquery判断对象是否为空

    1. jquery对象分为两种,一种是dom对象,dom对象会自带一个length属性,所以这种情况: obj.length == 0 可以判断对象为空 2. jquery也可以自定义对象,如 var ...

随机推荐

  1. ERROR: HHH000388: Unsuccessful: create table

    做SSH整合的时候,总是出现错误信息: 类似这样: : HHH000388: Unsuccessful: create table right (right_code varchar(255) not ...

  2. hdu 4751 Divide Groups(dfs染色 或 2-sat)

    Problem Description   This year is the 60th anniversary of NJUST, and to make the celebration more c ...

  3. OpenCV2马拉松第14圈——边缘检測(Sobel,prewitt,roberts)

    收入囊中 差分在边缘检測的角色 Sobel算子 OpenCV sobel函数 OpenCV Scharr函数 prewitt算子 Roberts算子 葵花宝典 差分在边缘检測究竟有什么用呢?先看以下的 ...

  4. PHP: configure: error: mysql configure failed. Please check config.log for more information.

    为php增加mysql模块时报错 configure: error: mysql configure failed. Please check config.log for more informat ...

  5. 使用zeranoe的自动化脚本mingw-w64-build-3.6.4在ubutun14.04_64bit上交叉编译ffmpeg 2.5

    编译期间,碰到的两个大问题,是环境变量设置问题. 先列出执行脚本是碰到的两个问题,后面给出解决方法并记录执行的命令步骤. 问题1: 编译binutils 2.5出错 ----------------- ...

  6. Windows Server 2008 R2 IIS重装

    背景描述: 在一个刚睡醒午觉后的下午,忽然收到客户反馈,说昨天开始应用特别卡,各种卡各种不好用,忽然想到上次说要优化服务器IIS配置还一直没弄,然后迷迷糊糊的就开始进行客户现场服务器IIS配置优化,涉 ...

  7. ie8下的透明 问题

    团队里经常遇到,索性整理一起 是我们在前端开发中经常遇到的,在问题中经常遇到的两个问题是背景色透明和整体透明 先说下背景色透明,背景色透明,在现代浏览器中,可以用rgba颜色作为背景色. 简单介绍下r ...

  8. github proxy

    --set github proxy git config --global http.proxy http://user_name:user_pwd@user_ip:port git config  ...

  9. 03-树1. List Leaves (25)

    Given a tree, you are supposed to list all the leaves in the order of top down, and left to right. I ...

  10. Nginx 变量漫谈(五)

    前面在 (二) 中我们已经了解到变量值容器的生命期是与请求绑定的,但是我当时有意避开了“请求”的正式定义.大家应当一直默认这里的“请求”都是指客户端发起的 HTTP 请求.其实在 Nginx 世界里有 ...