美文网首页
OBJDescription 格式化输出 解决字典数组自定义类的

OBJDescription 格式化输出 解决字典数组自定义类的

作者: AliceJordan | 来源:发表于2019-01-19 19:04 被阅读0次

    格式化输出

    最近在看52个方法这本书,其中有一个方法讲的就是关于编写Description方法的,这个方法我之前也有看过是关于打印对象信息的方法,这次看的时候突发奇想想去做一个Pod库 省的以后再去找方法改写,于是乎周末在家就写了一个OBJDescription,希望各位大大们多多提意见。

    关于输出

    这里就引用书上的一些描述,调试程序时,经常需要打印并且查看对象信息,一种方法是编写对象的全部属性都输出到日志中,像我们平时使用的NSLog一个变量,在调用NSLog的时候,对象会收到description消息,该方法所返回的描述信息将取代格式字符串里面的%@ 官方文档的解释 其实说白了就是要打印的内容。

    痛点

    在我们打印NSArray,NSDictionary对象的时候都可以显示出Array的元素内容的
    比如:

    NSArray *array = @[@"A",@"B"];
    NSLog(@"%@",array);
    
    输出:
    array = (
        "A",
        "B"
    )
    
    

    字典的输出也是类似的比较可以看出字典的内容,但是如我们自定义一个类,然后输出来看看就是类似于<类名: 对象的内存地址>

    这里图床挂了 这两天整下上传图片

    <Person:0X7facfabe1270>
    

    这样对于Debug的观察极其的舒服,我们看不到有用的信息啊。

    解决方法

    这个方法定义在NSObjc协议里,不过NSObject类也实现了他,因为NSObject并不是唯一一个跟类,所以许多方法都要定义在NSObjct协议里面,比方说,NSProxy也是一个遵循了NSObject协议的根类,由于description定义在协议里面,因此NSProxy和他的子类也是需要实现这个方法的,前面是书上说的,我并没抓到他们的因果关系,但是重要的一点是他所说的NSObject实现了这个方法,我的想法是通过NSObject的分类在分类中通过runtime获取到类的成员变量然后将他们组成成一个NSDictionary通过NSDictionary的description打印出来 这里的代码不是很复杂,就是利用runtime获取成员变量然后对于字符串的一些操作组成字典,返回给重写的description方法。

    // 重写description 方法
    - (NSString *)description
    {
        NSDictionary *dic = [self sharker_ivars];
        return [dic description];
    }
    
    // 获取成员变量
    - (NSDictionary *)sharker_ivars{
        NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
        unsigned int outCount = 0;
        Ivar * ivars = class_copyIvarList([self class], &outCount);
        for (unsigned int i = 0; i < outCount; i ++) {
            Ivar ivar = ivars[i];
            const char * name = ivar_getName(ivar);
            const char * type = ivar_getTypeEncoding(ivar);
            NSString *nameStr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            NSString *typeStr = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
            nameStr = [nameStr stringByReplacingOccurrencesOfString:@"_" withString:@""];
            typeStr = [typeStr stringByReplacingOccurrencesOfString:@"\"" withString:@""];
            typeStr = [typeStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
            typeStr = [typeStr stringByReplacingOccurrencesOfString:@"@" withString:@""];
            [dic setObject:[self valueForKey:nameStr] forKey:[NSString stringWithFormat:@"%@",nameStr]];
        }
        free(ivars);
        return [dic copy];
    }
    

    这里有遇到了一个问题就是关于字典中含有中午输出会出现乱码的情况,网上有很多这样的例子,我根据其中一个做了写修改,这里放出关于NSDictionary的关键代码

    /**
     格式化输出字典
    
     @param level 层级
     @return 格式化字符串
     */
    - (NSString *)sharker_descriptionWithLevel:(int)level{
        NSString *subSpace = [self sharker_getSpaceWithLevel:level];
        NSString *space = [self sharker_getSpaceWithLevel:level-1];
        NSMutableString *retString = [[NSMutableString alloc] init];
        //    添加 {
        [retString appendString:@"{"];
        [self enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            if ([obj isKindOfClass:[NSString class]]) {
                NSString *value = (NSString *)obj;
                value = [value stringByReplacingOccurrencesOfString:@"\0" withString:@"\\0"];
                NSString *subString = [NSString stringWithFormat:@"\n%@\"%@\" : \"%@\",",subSpace,key,value];
                [retString appendString:subString];
            }else if ([obj isKindOfClass:[NSDictionary class]]){
                NSDictionary *dic = (NSDictionary *)obj;
                NSString *str = [dic sharker_descriptionWithLevel:level+1];
                str = [NSString stringWithFormat:@"\n%@\"%@\" : %@,", subSpace, key, str];
                [retString appendString:str];
            }else if ([obj isKindOfClass:[NSArray class]]){
                NSArray *arr = (NSArray *)obj;
                NSString *str = [arr descriptionWithLocale:nil indent:level+1];
                str = [NSString stringWithFormat:@"\n%@\"%@\" : %@,", subSpace, key, str];
                [retString appendString:str];
            }else{
    //            字典的属性是其他类型 可以空充需要的打印方式
                NSString *str = [NSString stringWithFormat:@"\n%@\"%@\" : %@,", subSpace, key, obj];
                [retString appendString:str];
            }
        }];
        if ([retString hasPrefix:@","]) {
            [retString deleteCharactersInRange:NSMakeRange(retString.length-1, 1)];
        }
        //    添加 }
        [retString appendString:[NSString stringWithFormat:@"\n%@}",space]];
        return retString;
    }
    

    思路还是很简单的就是通过判断类型,然后格式化输出,乱码的解决就是转化为字符串输出就好了,里面还包含了像是字典嵌套的的情况,通过获取层级,添加空格使得输出的效果更好。

    相关话题

    • debugDescription

      这里关于打印还有几个方法,其中想debugDescription就是我们平时在使用lldb调试po调用的,但是如果没有特殊实现的话他其实最后就是调用的description方法,如果我们觉得信息不够全面可以在debugDescription方法里面添加,这个方法只会在控制台,用lldb时输出。

    • descriptionWithLocale:indent

      ==*注:优先级 - (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level > - (NSString *)description 这个方法是被NSArray 与 NSDictionary 实现的方法
      官方描述
      总的说就是为了输出的格式化与美观性.

    关于

    最后放出demon的地址GitHub

    作者 Sharker
    邮箱 aaksharker@gmail.com
    QQ 1548742234

    参考阅读 谢谢各位的分享
    参考
    参考
    参考

    相关文章

      网友评论

          本文标题:OBJDescription 格式化输出 解决字典数组自定义类的

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