打印对象和description
定义与理解
description方法是NSObject类的一个实例方法,所有的Objective-C都是NSObject类的子类,因此,所有的Objective-C对象 都具有description方法。
description方法是一个非常特殊的方法,它是一个“自我描述”方法,该方法通常用于实现这样一个功能:当程序员直接打印该对象时,系统将会输出该对象的“自我描述”功能,用以告诉外界该对象具有的状态信息。
NSObject类提供的description方法总是返回<FKPerson: 16进制的首地址>,这个返回值并不能真正实现“自我描述”的功能,因此,如果用户需要自定义类能实现“自我描述”的功能,必须重写NSObject类的description方法。
大部分时候,重写description方法总是返回该对象所有令人感兴趣的信息所组成的字符串,通常可返回如下格式的字符串:
<类名[实例变量1 = 值1, 实例变量2 = 2,…]>
实例
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FKApple : NSObject
@property (nonatomic , copy)NSString* color;
@property (nonatomic , assign)double weight;
-(id) initWithColor: (NSString*) color weight: (double) weight;
@end
NS_ASSUME_NONNULL_END
#import "FKApple.h"
@implementation FKApple
@synthesize color = _color;
@synthesize weight = _weight;
-(id) initWithColor:(NSString *)color weight:(double)weight
{
if (self = [super init])
{
self.color = color;
self.weight = weight;
}
return self;
}
-(NSString*) description
{
return [NSString stringWithFormat:@"<FKApple[_color=%@, _weight=%g]>", self.color, self.weight];
}
@end
#import <Foundation/Foundation.h>
#import "FKApple.h"
int main(int argc , char * argv[])
{
@autoreleasepool {
FKApple* a = [[FKApple alloc] initWithColor:@"红色" weight:2.58];
NSLog(@"%@", a);
}
}
我们看一下运行结果:
所以当我们重新写了description方法时,我们想要的结果就出来了,它告诉了我们颜色和重量的内容。
==和isEqual方法
我们都知道==运算符,它在判断两个变量是否相等时,如果两个变量是基本类型的变量,且都是数值型(不一定要求数据类型完全相同),则只要两个变量的值相等,使用 ==判断并返回真。
对于两个指针类型的变量,它们必须指向同一个对象(也就是两个指针变量保存的内存地址相同)时, ==判断才会返回真。当使用 ==比较类型上没有继承关系的两个指针变量时,编译器回提示警告,下面程序示范了使用 ==来判断两种类型变量是否相等的结果。
#import <Foundation/Foundation.h>
#import "FkPerson.h"
int main(int argc , char * argv[])
{
@autoreleasepool {
int it = 65;
float f1 = 65.0f;
NSLog(@"65和65.0f是否相等?:%d", (it == f1));//将输出1代表真
char ch = 'A';
NSLog(@"65和'A'是否相等? %d",(it == ch));//将输出1代表真
NSString* str1 = [NSString stringWithFormat:@"hello"];
NSString* str2 = @"hello";
NSLog(@"str1和str2是否相等?%d", (str1 == str2));
NSLog(@"str1是否isEqualstr2?%d",[str1 isEqual: str2]);
}
}
运行结果如图所示:
我们可以看到,65、65.0f和’A’相等。但对于str1和str2,因为它们都是指针类型变量,它们分别指向两个通过NSString的静态方法创建出来的NSString对象,因此str1和str2两个变量不相等。
常量池
==常量池保证相同的字符串直接量只有一个,不会产生多个副本。==我们使用NSString stringWithFormat:类方法创建的字符串对象是运行时创建出来的,它被保存在运行时内存区(即堆内存),不会放入常量池中。
代码展示:
#import <Foundation/Foundation.h>
#import "FkPerson.h"
int main(int argc , char * argv[])
{
@autoreleasepool {
//s1、s2直接指向常量池中的"疯狂iOS"
NSString* s1 = @"疯狂iOS";
NSString* s2 = @"疯狂iOS";
//看到s1、s2两个指针保存的地址完全相等
NSLog(@"s1地址:%p, s2的地址:%p", s1, s2);
//所以下面的程序输出1代表真
NSLog(@"s1与s2是否相等: %d", (s1 == s2));
//让s3指向新生成的对象
NSString* s3 = [NSString stringWithFormat:@"疯狂iOS"];
//输出s3指针变量中保存的地址值与s1、s2并不相同
NSLog(@"s3地址:%p", s3);
//所以下面的程序输出0代表假
NSLog(@"s1与s3是否相等: %d", (s1 == s3));
}
}
我们可以看到NSString stringWithFormat:类方法创建的字符串对象是运行时创建出来的,它被保存在运行时内存区(即堆内存),不会放入常量池中,所以它和s1、s2虽然是同样的一句话可是地址不一样用==判断结果为假。
重写isEqual: 方法
如果我们想让isEqual:方法来实现自定义标准,那么我们就需要在实现部分重写isEqual:方法。
虽然NSString已经重写了最开始NSObject的isEqual:方法:NSString判断两个字符串的标准是:只要两个字符串所包含的字符序列相同,则返回真,否则返回假。
代码如下:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FKUser : NSObject
@property (nonatomic , copy) NSString* name;
@property (nonatomic , copy) NSString* idStr;
-(id) initWithName: (NSString*) name
idStr: (NSString*) idStr;
@end
NS_ASSUME_NONNULL_END
#import "FKUser.h"
@implementation FKUser
@synthesize name = _name;
@synthesize idStr = _idStr;
-(id) initWithName:(NSString *)name idStr:(NSString *)idStr
{
if (self = [super init])
{
self.name = name;
self.idStr = idStr;
}
return self;
}
-(BOOL) isEqual:(id)other
{
if (self == other)
{
return YES;
}
if (other != nil && [other isMemberOfClass:FKUser.class])
{
FKUser* target = (FKUser*)other;
return [self.idStr isEqual:target.idStr];
}
return NO;
}
@end
#import <Foundation/Foundation.h>
#import "FKUser.h"
int main(int argc , char * argv[])
{
@autoreleasepool {
FKUser* p1 = [[FKUser alloc] initWithName:@"孙悟空" idStr:@"12343433433"];
FKUser* p2 = [[FKUser alloc] initWithName:@"孙行者" idStr:@"12343433433"];
FKUser* p3 = [[FKUser alloc] initWithName:@"孙悟饭" idStr:@"99933433"];
NSLog(@"p1和p2是否相等?%d", [p1 isEqual: p2]);
NSLog(@"p2和p3是否相等?%d", [p2 isEqual: p3]);
}
}
运行结果如图所示:
我们可以看到,p1和p2的地址相等,所以[p1 isEqual : p2]返回值为1,而又因为p2和p3的地址不相等,所以[p2 isEqual : p3]返回值为0。重新了isEqula:方法后,我们就可以比较两个对象是否相等。
正确重写isEqual:方法要满足的条件
- 自反性:对任意x,[x isEqual: x]一定返回真。
- 对称性:对任意x和y,如果[x isEqual: y]返回真,则[y isEqual: x]一定返回真。
- 传递性:对任意x、y、z,如果[x isEqual: y]返回值,[y isEqual: x]返回真,则[x isEqual: z]一定返回真。
- 一致性:对任意x和y,如果对象中用于等价比较的关键消息没有改变,那么无论调用[x isEqual: y]多少次,返回的结果应保持一致,要么一直是真,要么一直是假。
- 对任何不适nil的x,[x isEqual : nil]一定返回假。