调试程序时,经常需要打印并查看对象信息。一种方法是编写代码把对象的全部属性都输出到日志中。最常用做法像下面这样:
NSLog(@"object = %@", object);
复制代码
1
在构建需要打印到日志的字符串时, object 对象会收到 description 消息, 该方法所返回的描述信息将取代 “格式字符串”(format string) 里的 “%@”。比方说, object 是个数组,若用下列代码打印其信息:
NSArray *object = @[@"A string", @(123)];
NSLog(@"object = %@", object);
其输出结果:
object = ("A string",
123
)
然而,如果在自定义的类上面这么做, 那么输出的信息确下面这样:
object = <EOCPerson: 0x7fd9a1600600>
复制代码
与object为数组时所输出的信息相比,上面这种内容不太有用。除非在自己的类里覆写 description 方法,否则打印信息时就会调用NSObject类所实现的默认方法。此方法定义在NSObject协议里,不过NSObject类也实现了它。因为NSObject并不是唯一的“根类”,所以许多方法都要定义在NSObject协议里。比方说,NSProxy也是一个遵从了NSObject协议的“根类”。由于description等方法定义在NSObject协议里,因此像NSProxy这种“根类”及其子类也必须实现它们。
要想输出更为有用的信息也很简单,只需覆写description方法并将描述此对象的字符串返回即可。例如:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MJPerson : NSObject
@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName;
- (id)initWithFirstName: (NSString *)firstName lastName:(NSString *)lastName;
@end
NS_ASSUME_NONNULL_END
复制代码
#import "MJPerson.h"
@implementation MJPerson
- (id)initWithFirstName: (NSString *)firstName lastName:(NSString *)lastName {
if(self = [super init]){
_firstName = [firstName copy];
_lastName = [lastName copy];
}
return self;
}
//该类的description方法通常可以这样实现:
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p, \"%@ %@\">",
[self class], self, _firstName, _lastName];
}
@end
复制代码
假如按上面的代码来写,那么ZZBPerson 对象就会输出如下格式信息:
#import "ViewController.h"
#import "MJPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MJPerson *person = [[MJPerson alloc] initWithFirstName:@"Bob" lastName:@"Smith"];
NSLog(@"person = %@", person);
//打印结果:
//<MJPerson: 0x600002109440, "Bob Smith">
}
@end
复制代码
显而易见就比覆写之前所输出的信息更加清楚,更为有用。
NSObject协议中还有个方法要注意,那就是debugDescription, 此方法的用意与description非常相似。二者的区别在于,debugDescription方法是开发者在调试器中以控制台命令打印对象时才调用的。在NSObject类的默认实现中,此方法只是直接调用description。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END