OC对象都是NSObject的子类的实例,而NSObject为我们提供了一些处理OC对象的通用方法。
打印对象和description方法
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic, copy)NSString *name;
- (id)initWithName:(NSString *)name;
- (void)info;
@end
@implementation Person
@synthesize name = _name;
- (id)initWithName:(NSString *)name {
if(self = [super init]) {
self.name = name;
}
return self;
}
- (void)info {
NSLog(@"姓名:%@", self.name);
}
@end
int main() {
@autoreleasepool {
//创建一个Person对象,并把它赋给p变量
Person *p = [[Person alloc] initWithName:@"顶梁柱"];
//打印p指向的Person变量
NSLog(@"%@", p);
NSLog(@"%@", [p description]);
}
}
输出:
可以看出, p 和 [p description] 在NSLog里的输出相同,这是因为description是一个“自我描述”的方法,它返回该对象的16进制下首地址。但是,这个首地址并不能完全实现自我描述,我们可以通过重写description方法来实现我们想要的自述。
#import <Foundation/Foundation.h>
@interface Apple : NSObject
@property(nonatomic, copy)NSString *color;
@property(nonatomic, assign)double weight;
- (id)initWithColor:(NSString *)color andWeight:(double) weight;
@end
@implementation Apple
- (id)initWithColor:(NSString *)color andWeight:(double) weight {
if(self = [super init]) {
self.color = color;
self.weight = weight;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<Apple[_color=%@, weight=%g]>", self.color, self.weight];
}
@end
int main() {
@autoreleasepool {
Apple *a = [[Apple alloc] initWithColor:@"红色" andWeight:2.33];
NSLog(@"%@", a);
}
}
输出:
通过重写description,我们实现了我们想要的功能:对该对象进行自我描述。
==和isEqual方法
OC中测试两个变量是否相等有两种方式:== 运算符和isEqual方法。
当用 == 运算符时,如果连个变量都是基本数据类型,且都是数值型(类型不要求严格相同),则只要两个变量的值相等,使用 == 就将返回真(如65 = 65.0 = ‘A’ );对于两个指针类型的变量,它们必须指向同一个对象, == 判断才会为真。当比较类型上没有继承关系的两个指针变量时,编译器会提示警告。
在讨论具体isEqual方法之前,有一个问题:@"hello"直接量和 [NSString stringWithFormat:@“hello”] 有什么区别?
其实当OC程序直接使用形如@"hello"字符串直接量时,系统将会使用常量池来管理这些字符串,常量池保证相同的字符串直接量只有一个,不会产生多个副本。而通过NSString stringWithFormat:类方法创建的字符串对象是运行时创建的,它被保存在运行时内存区内(堆内存),不会放入常量池中。
因此以第1种方式创建的字符串不论有多少,只要是同一个字符串, == 会判断它们相等;而以第2种方式创建的字符串对象保存地址不相同,因此 == 会判断它们不等。
NSObject提供了isEqual实例方法,但它只是比较对象的地址,这个方法判断两个对象相等的标准与 == 没有区别,要求两个对象指向同一个对象才会返回真值。
NSString对象的isEqual方法可以判断两个字符串变量的字符串序列是否相等,即使使用NSString stringWithFormat:创建的两个对象不一样,只要其指向的字符串序列相同,isEqual就会给我们“真”的结果。
NSString已经重写了NSObject的isEqual方法,如果我们想要判断两个对象是否符合我们自定义的相等标准,可以重写isEqual方法。
#import <Foundation/Foundation.h>
@interface Dog : NSObject
@end
@implementation Dog
- (BOOL)isEqual:(id)other {
//不进行判断,该对象与任何对象都相等
return YES;
}
@end
@interface Item : NSObject
@end
@implementation Item
@end
int main() {
@autoreleasepool {
Dog *p = [[Dog alloc] init];
NSLog(@"Dog对象是否与Item对象isEqual: %d", [p isEqual:[Item new]]);
NSLog(@"Dog对象是否与NSString对象isEqual: %d", [p isEqual:[NSString stringWithString:@"hello"]]);
}
}
输出:
如果不进行isEqual方法的重写,输出为:
在实际的isEqual重写中,我们可以添加自己的标准,但是要注意应满足的条件:
- 自反性:对任意x, [x isEqual: x] 一定返回真
- 对称性:对任意x和y,如果 [y isEqual: x] 返回真,则 [x isEqual: y] 也返回真
- 传递性:对任意x、y、z,如果 [x isEqual: y] 返回真, [y isEqual: z] 返回真,则 [x isEqual: z] 返回真
- 一致性:对任意x和y,如果对象中用于判断等价的关键信息没有改变,返回结果应该是一致的
NSString不仅重写了isEqual方法,还定义了isEqualToString方法,该方法用于专门比较两个字符串是否相等。实际上,OC还为我们提供了isEqualToArray、isEqualToClass等对于某特定类对象的比较方法,这增加了代码的可读性,也是OC语言的一大亮点。