iOS打印模型属性值与断点调试

前言:在实际开发中,我们经常会使用断点调试,来获得在某一步操作之后,程序中某一对象的所有属性值。 但是当需要频繁更改并实时获取该对象属性值得时候,使用断点调试会浪费大量的等待时间,相比之下,使用NSLog暴力输出会显得更方便快速,这时我们就要结合重写对象的description方法来打印当前属性值。


问题阐述:

一般情况下,我们会使用断点调试的方式,来获取某一操作之后,程序中某一对象的属性值。 例如,新建Student类,并对其进行赋值:

#import <Foundation/Foundation.h>

@interface StudentModel : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *city;
@property (nonatomic, copy) NSString *country;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) NSInteger sex;

@end
复制代码
- (void)setData{
    _model = [[StudentModel alloc]init];
    _model.name = @"Samson";
    _model.city = @"FuYang";
    _model.country = @"China";
    _model.age = 24;
    _model.sex = 1;
    
}

复制代码

在图中所示位置设置断点,进行调试,可以得到当前该对象的所有属性值:

但是当我们需要在项目运行时,频繁更改或者获取对象的属性值时,使用断点调试会浪费不少的时间,这是我们想到了NSLog打印语句。在上图中去掉断点,查看此时的打印结果:

这时NSLog语句只打印出了对象的类名和地址,显然不是我们想要的输出信息。

解决方式: 我们一般通过重写对象的description方法来打印出所需要的属性值。 例如我们需要获得Student对象的name、city和age属性值时,通常重写方式为:


- (NSString *)description{
   
    return [NSString stringWithFormat:@"name:%@\n city:%@\n age:%ld",self.name,self.city,self.age];
    
}
复制代码

此时查看NSLog打印语句输出信息:

正确打印出我们需要的结果。

**问题思考:**这样做能打印出我们设定好的属性值,但是当我们动态为该对象添加或者删除属性时,这种方式却不能实时打印出对象的所有属性值,这时我们要对处理方式进行优化。

方法优化: 什么是objc_property_t: objc_property_t是表示Objective-C声明的属性的类型,其实际是指向objc_property结构体的指针,其定义如下:

/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;
复制代码

我们通过objc_property_t在description方法中动态获取对象当前的属性列表,并进行赋值打印:

- (NSString *)description{
   
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    
    for (int i = 0; i < count; i++) {
        
        NSString *name = [NSString stringWithFormat:@"%s",property_getName(properties[i])];
        
        id value = [self valueForKey:name] ?:@"nil";
        
        [dict setObject:value forKey:name];
    }
    
    free(properties);
    return [NSString stringWithFormat:@"<%@:%p>:%@",[self class],self,dict];
    
}
复制代码

查看此时打印结果:

如果要将断点调试时po命令打印信息也改为对象所有属性值,则需要重写对象的debugDescription方法:

- (NSString *)debugDescription{
    
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    
    uint count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    
    for (int i = 0; i < count; i++) {
        
        NSString *name = [NSString stringWithFormat:@"%s",property_getName(properties[i])];
        
        id value = [self valueForKey:name] ?:@"nil";
        
        [dict setObject:value forKey:name];
    }
    
    free(properties);
    return [NSString stringWithFormat:@"<%@:%p>:%@",[self class],self,dict];
}
复制代码

在实际使用时,我们不可能在每个对象中都对这两个方法进行重写。这时,可以自定义工具类对其进行方法重写:

- (NSString *)description{
   
    return [MyControl getDescriptionWithObjc:self];
    
}
复制代码

并且在方法实现中进行相关的逻辑处理:

+ (NSString *)getDescriptionWithObjc:(id)objc{

    //如果不是要打印自定义类的属性,直接实现原有的description方法即可
    if ([objc isKindOfClass:[NSArray class]] || [objc isKindOfClass:[NSDictionary class]] || [objc isKindOfClass:[NSString class]] || [objc isKindOfClass:[NSNumber class]]) {
        return [objc description];
    }
    
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    
    uint count;
    objc_property_t *properties = class_copyPropertyList([objc class], &count);
    
    for (int i = 0; i < count; i++) {
        
        NSString *name = [NSString stringWithFormat:@"%s",property_getName(properties[i])];
        
        id value = [objc valueForKey:name] ?:@"nil";
        
        [dict setObject:value forKey:name];
    }
    
    free(properties);
    return [NSString stringWithFormat:@"<%@:%p>:%@",[objc class],objc,dict];
}
复制代码

转载于:https://juejin.im/post/5a31d4d06fb9a0452936c3eb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值