美文网首页
Runtime打印自定义类型属性-2021-02-23-周二

Runtime打印自定义类型属性-2021-02-23-周二

作者: 勇往直前888 | 来源:发表于2021-02-23 18:12 被阅读0次

在开发当中,我们很多时候需要打印自定义类型的所有属性。如果我们直接使用NSLog(@"%@",person);的方式,打印出来只是person的内存地址

image.png
  • NSLog(@"%@",person);实际上是执行了Person的方法- (NSString *)description;
    调试时的po,实际上执行了Person的方法- (NSString *)debugDescription;
    所以我们考虑重写person的这两个方法来实现目的

Person定义

@interface Person : NSObject

// 姓名;公共属性
@property (nonatomic, copy) NSString *name;

// 年龄;公共属性
@property (nonatomic, assign) NSInteger age;

@end
@interface Person ()

// 昵称;私有属性
@property (nonatomic, copy) NSString *nickname;

@end

这样我们就定义了name,age两个公共属性;nickname一个私有属性

遍历属性

runtime提供了函数class_copyPropertyList可以得到一个对象的所有属性,包括公有属性和私有属性

第1种思路是将得到的属性转化为一个字典,以属性的名字为key;字典已经实现了那两个Description方法,可以自动打印

// 将本身的属性列表转化为一个字典
// 注意NSDictionary的Description无法显示中文
- (NSDictionary *)propertyDictionary {
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    // 遍历数组,并利用kvc得到每个属性的值
    for (int i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        // C函数得到的是C类型字符串,char类型数组或者指针
        const char *propertyName = property_getName(property);
        NSString *name = [NSString stringWithUTF8String:propertyName];
        // 利用KVC得到值,默认为值为nil字符串
        id value = [self valueForKey:name] ?: @"nil";
        // 添加到字典中
        [dictionary setObject:value forKey:name];
    }
    
    // 释放
    free(properties);
    
    return [dictionary copy];
}
#pragma mark - 重写描述方法
// NSLog会执行这个方法
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p> %@", [self class], self, [self propertyString]];
}

// po会执行这个方法
- (NSString *)debugDescription {
    return [NSString stringWithFormat:@"<%@: %p> %@", [self class], self, [self propertyString]];
}

测试一下

- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化
    self.person = [[Person alloc] init];
    
    // 公共属性,可以在外部设置
    self.person.age = 30;
    self.person.name = @"小明";
    // nickName是私有属性,无法设置
    NSLog(@"%@", self.person);
}
  • 控制台输出:
2021-02-23 18:04:54.166723+0800 RuntimeDemo[7462:510849] <Person: 0x60000386c3a0> {
    age = 30;
    name = "\U5c0f\U660e";
    nickname = nil;
}

问题:无法显示中文

设置内容:self.person.name = @"小明";

打印内容:name = "\U5c0f\U660e";

这是字典的Description函数导致,直接给出了Unicode编码,而不是对应的中文

如何解决

字典的Description函数没有进行Unicode解码,可是NSString可以啊;所以思路很简单,直接把属性的namevalue拼接成NSString

// 将本身的属性列表拼接为一个字符串
// 自己拼接NSString,可以解决Unicode问题,比如显示中文
- (NSString *)propertyString {
    NSMutableString *resultString = [NSMutableString string];
    [resultString appendString:@"{\n"];
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    // 遍历数组,并利用kvc得到每个属性的值
    for (int i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        // C函数得到的是C类型字符串,char类型数组或者指针
        const char *propertyName = property_getName(property);
        NSString *name = [NSString stringWithUTF8String:propertyName];
        // 利用KVC得到值,默认为值为nil字符串
        id value = [self valueForKey:name] ?: @"nil";
        // 添加到结果字符串中
        [resultString appendFormat:@"  %@ = %@;\n", name, value];
    }
    [resultString appendString:@"}"];
    
    // 释放
    free(properties);
    
    return [resultString copy];
}
  • 再试一下,就能输出中文了
2021-02-23 18:10:56.976383+0800 RuntimeDemo[7486:514243] <Person: 0x600001e6c200> {
  nickname = nil;
  name = 小明;
  age = 30;
}

参考文章

iOS模型打印

Demo地址

RuntimeDemo

相关文章

网友评论

      本文标题:Runtime打印自定义类型属性-2021-02-23-周二

      本文链接:https://www.haomeiwen.com/subject/lefdfltx.html