Objective-C——判断对象等同性
无论我们使用什么语言,总是会出现需要判断两个对象是否相等的情况,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——判断对象等同性的更多相关文章
- Effective Objective-C 2.0 — 第8条:理解“对象等同性”这一概念
第8条:理解“对象等同性”这一概念 若想检测对象的等同性,请提供“isEqual”与 hash 方法 相同的对象必须具有相同哈希码,但是两个哈希码相同的对象却未必相同. 不要盲目地逐个检测每条属性,而 ...
- 如何理解iOS的“对象等同性”
在iOS开发过程中,我们经常需要用到等同性来判断两个对象是否相等,通常我们会使用==来判断,但是这样比较出来的结果可能不是我们期望的:所以,一般我们会使用NSObject协议声明的isEqual方法来 ...
- 深入Java虚拟机--判断对象存活状态
程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的.这个三个部分的特点 ...
- js中判断对象具体类型
大家可能知道js中判断对象类型可以用typeof来判断.看下面的情况 <script> alert(typeof 1);//number alert(typeof "2" ...
- java虚拟机判断对象是否存活的方式
引用计数算法: 给对象添加一个引用计数器,每当有地方应用时,计数器值就加一,当引用失效时,程序计数器就减一,只要引用计数器的值为零时,就表示对象不可能再被引用,例如微软的 component ob ...
- 将对象的所有属性名放到一个数组中 || 获得对象的所有属性名 || return;不具有原子性 || 怎样自己制作异常|| 判断对象有没有某个属性 || 当传递的参数比需要的参数少的时候,没有的值会被赋予undefined || 获得函数实际传递的参数 || 怎么用函数处理一个对象 || 用一个名字空间定义一个模块所有的函数 || 给一个对象添加方法
获得对象的所有属性名 || 将对象o的所有属性名放到数组中 var o = {x:1,y:2,z:3}; var arr = []; var i = 0; for(arr[i++] in o){};/ ...
- JavaScript中判断对象类型方法大全1
我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...
- freemarker判断对象是否为空
freemarker中显示某对象使用 ${name}. 但如果name为null,freemarker就会报错.如果需要判断对象是否为空: <#if name??> …… </# ...
- 关于jquery判断对象是否为空
1. jquery对象分为两种,一种是dom对象,dom对象会自带一个length属性,所以这种情况: obj.length == 0 可以判断对象为空 2. jquery也可以自定义对象,如 var ...
随机推荐
- 设置Android设备在睡眠期间始终保持WLAN开启的代码实现
MainActivity例如以下: package cc.ab; import android.os.Bundle; import android.provider.Settings; import ...
- Java String类具体解释
Java String类具体解释 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,非常多时候,我们对它既熟悉又陌生. 类结构: public fin ...
- 深入浅出:重温JAVA中接口与抽象的区别
抽象类:声明一个抽象类,就是在类的声明开头.在Class关键字的前面使用关键字abstract 下面定义一个抽象类,代码如下: abstract class A{ abstract void call ...
- [Python笔记][第一章Python基础]
2016/1/27学习内容 第一章 Python基础 Python内置函数 见Python内置函数.md del命令 显式删除操作,列表中也可以使用. 基本输入输出 input() 读入进来永远是字符 ...
- 淘宝对接API
最近在忙与淘宝做对接的工作,总体感觉淘宝的api文档做的还不错,不仅有沙箱测试环境,而且对于每一个api都可以通过api测试工具生成想要的代码,你完全可以先在测试工具中测试之后再进行代码的编写,这样就 ...
- application,session,cookie三者之间的区别和联系
application: 程序全局变量对象,对每个用户每个页面都有效 session: 用户全局变量,对于该用户的所有操作过程都有效 session主要是在服务器端用,一般对客户端不 ...
- 【原创】System.Data.SQLite内存数据库模式
对于很多嵌入式数据库来说都有对于的内存数据库模式,SQLite也不例外.内存数据库常常用于极速.实时的场景,一个很好的应用的场景是富客户端的缓存数据,一般富客户端的缓存常常需要分为落地和非落地两种,而 ...
- weblogic配置domain和删除domain
weblogic创建域的过程比较简单,但是在创建域之前一定要注意不能存在重名的domain. Domain简单定义为:是一个逻辑管理单元,Domain下面包含着weblogic应用服务器中的所有东西, ...
- windows 文件watch nodejs
本篇博客,主要是记录下最近一直纠结的gulp.watch方法,在工作中我们肯定都遇到过,新添加的文件没办法自动触发watch,下面我们就来看有什么办法处理 1.首先我们肯定是先百度一下 百度推荐的是g ...
- Cube(hd1220)
Cube 点我 Problem Description Cowl is good at solving math problems. One day a friend asked him such a ...