好玩的debugDescription(debug模式下调试model)

PhilShumate 9年前

来自: http://www.jianshu.com/p/4e1f6938c1ca

description

在开发过程中, 往往会有很多的model来装载属性. 而在开发期间经常会进行调试查看model里的属性值是否正确. 那么问题来了, 在 objective-c 里使用 NSLog("%@",model) 这行代码打印出来的却是 model 的地址. 不是我们所想要的结果~! 看图:

那么问题又来了?有没有办法解决这个问题尼,答案那就是有~!只需要重写 - (NSString *)description 方法即可。如下代码:

.h文件

#import <Foundation/Foundation.h>    @interface TestModel : NSObject  @property (copy,nonatomic) NSString *text;  @property (assign,nonatomic) NSInteger index;  @end

.m文件

#import "TestModel.h"    @implementation TestModel  - (NSString *)description {      return [NSString stringWithFormat:@"text:%@--index:%zi",self.text,self.index];  }  @end

然后这时候在使用 NSLog("%@",model) 这行代码就能打印我们想要的结果了。 看如下图:

那么问题继续来了...

如果model里有 N 多个属性尼, 可能 10 个, 可能 20 个... 难道要在 description 方法里一个一个写属性并拼接返回? 你不嫌麻烦, 我光看着都蛋疼了... 所以我们可以采用 runtime 技术来动态获取属性并返回. 如下修改后的.m文件代码:

</div>

修改后的.m文件

#import "TestModel.h"  #import <objc/runtime.h>//导入runtime头文件    @implementation TestModel  - (NSString *)description {      //初始化一个字典      NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];        //得到当前class的所有属性      uint count;      objc_property_t *properties = class_copyPropertyList([self class], &count);        //循环并用KVC得到每个属性的值      for (int i = 0; i<count; i++) {          objc_property_t property = properties[i];          NSString *name = @(property_getName(property));          id value = [self valueForKey:name]?:@"nil";//默认值为nil字符串          [dictionary setObject:value forKey:name];//装载到字典里      }        //释放      free(properties);        //return      return [NSString stringWithFormat:@"<%@: %p> -- %@",[self class],self,dictionary];  }  @end

然后在打印 model , 如下图:

这里写图片描述
</div> </div>

debugDescription

现在问题继续来了..

在项目中 NSLog 语句往往也很多. 如果重写 description 方法. 在控制台则会打印出很多属性. 看着就不舒服~~而且还有一个问题就是, 有时候我们其实并不需要打印 model 的属性.. 那这样重写 description 方法反而 适得其反 了! 所有, 现在有一个解决方案就是重写 debugDescription 方法

什么是 debugDescription ? 其实 debugDescription 和 description 是一样的效果. 只不过唯一的区别就是 debugDescription 是在 Xcode 控制台里使用 po 命令的时候调用的~!

而 debugDescription 的实现其实也就是调用了 description 方法而已

so, 在开发过程中并且 model 调试的时候, 笔者推荐重写 debugDescription 方法而不是重写 description 方法. 当需要打印 model 的属性的时候, 在控制台里使用 po 命令即可. 如下在此修改后的 .m文件

</div>
#import "TestModel.h"  #import <objc/runtime.h>//导入runtime头文件    @implementation TestModel    // 重写debugDescription, 而不是description  - (NSString *)debugDescription {      //声明一个字典      NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];        //得到当前class的所有属性      uint count;      objc_property_t *properties = class_copyPropertyList([self class], &count);        //循环并用KVC得到每个属性的值      for (int i = 0; i<count; i++) {          objc_property_t property = properties[i];          NSString *name = @(property_getName(property));          id value = [self valueForKey:name]?:@"nil";//默认值为nil字符串          [dictionary setObject:value forKey:name];//装载到字典里      }        //释放      free(properties);        //return      return [NSString stringWithFormat:@"<%@: %p> -- %@",[self class],self,dictionary];  }  @end

看如下图, 分别使用了 NSLog 和 po 命令的打印

这里写图片描述
</div>

结果:

这里写图片描述
</div>

这就达到了我们想要的效果, 如果需要打印 model 的属性, 打个断点然后使用 po 命令即可

</div>

demo地址

最后,附上本文章的一个小demo示例代码,已放在github上。

https://github.com/DemoMania/DebugDescriptionDemo

总结

  • model 调试的时候, 推荐重写 debugDescription 而不是 description
  • 利用 runtime 技术动态获取 class 的属性
  • 在 base 基类里重写 debugDescription 方法,随后所有model继承与 baseModel 即可。
  • 在重写的 debugDescription 的方法里最好不要调用自身 debugDescription([self debugDescription])
</div>