一行代码解决:服务器返回null导致应用崩溃

背景1:是否有这样一种感受,你的应用会崩溃,查看崩溃日志或者调试发现后台返回的数据字段里面有null,这个null居然还是导致应用崩溃的“元凶”。

背景2:服务器返回的字段名和不一致,如果model属性少,你可以一个个对应赋值,多了肯定都会想到用运行时机制来赋值:

[self setValue:temDic[key] forKeyPath:key],这时候需要对两个地方的字段做映射。


思路:1、先判断是否需要映射 2、把服务器返回的数据赋给model 3、model属性null检查(不同类型赋不同值,并不是把所有null都赋@"")4、这个写法应该适应所有自定义的类型,所有给NSObject 加一个Category。




#import "NSObject+runtime.h"


@implementation NSObject (runtime)


- (void)fetchValueFormNetDict:(NSDictionary *)dic andMapDic:(NSDictionary *)MapDic{

    

     NSArray *properties = [self getAllProperties];

    //需要映射

    if (MapDic != nil) {

        

        NSArray *allKeys = dic.allKeys;

        

        NSMutableDictionary *temDic = [NSMutableDictionary dictionaryWithCapacity:allKeys.count];

        

        for (int i = 0; i < allKeys.count; i ++) {

            

            NSString *key = allKeys[i];

            

            [temDic setObject:dic[key] forKey:MapDic[key]];

        }

        

        // 遍历属性数组

        for (NSString *key in properties) {

            // 判断字典中是否包含这个key

            [self setValue:temDic[key] forKeyPath:key];

        }


    }

    else//不需要映射

    {

       

        // 遍历属性数组

        for (NSString *key in properties) {

            // 判断字典中是否包含这个key

            [self setValue:dic[key] forKeyPath:key];

        }


    }

    //null 或者 nil 处理

    [self nullDeal];

    

}


//获取所有的属性名

- (NSArray *)getAllProperties

{

    u_int count;

    objc_property_t *properties  =class_copyPropertyList([self class], &count);

    NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i<count; i++)

    {

        const char* propertyName =property_getName(properties[i]);

        [propertiesArray addObject: [NSString stringWithUTF8String: propertyName]];

    }

    free(properties);

    return propertiesArray;

}


-(void)nullDeal

{

    //找到属性对应的类型

    NSDictionary *typeDic = [self classPropsFor:[self class]];

    NSArray *arr = typeDic.allKeys; //所有属性名字

    

    for (int i = 0; i < arr.count; i++) {


        //属性类型名字(字符串格式)

        NSString *typeString = typeDic[arr[i]];

        

        if ([[self valueForKey:arr[i]] isKindOfClass:[NSNull class]] || [self valueForKey:arr[i]] == nil) {

            

            if ([typeString isEqualToString:@"NSArray"]) {

                

                [self setValue:@[] forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"NSString"]) {

                

                [self setValue:@"" forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"NSNumber"]) {

                

                [self setValue:@0 forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"NSDictionary"]) {

                

                [self setValue:@{} forKey:arr[i]];

            }

            

            if ([typeString isEqualToString:@"B"]) {

                

                [self setValue:0 forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"f"]) {

                

                [self setValue:0 forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"d"]) {

                

                [self setValue:0 forKey:arr[i]];

            }

            if ([typeString isEqualToString:@"i"]) {

                

                [self setValue:0 forKey:arr[i]];

            }

        }

    }

    

   

    

}


//获取属性名称数组

- (NSDictionary *)classPropsFor:(Class)klass

{

    if (klass == NULL) {

        return nil;

    }

    

    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];

    

    unsigned int outCount, i;

    objc_property_t *properties = class_copyPropertyList(klass, &outCount);

    for (i = 0; i < outCount; i++) {

        objc_property_t property = properties[i];

        const char *propName = property_getName(property);

        if(propName) {

            

            const char *propType = getPropertyType(property);

            NSString *propertyName = [NSString stringWithUTF8String:propName];

            NSString *propertyType = [NSString stringWithUTF8String:propType];

            

            NSLog(@"propertyName %@ propertyType %@", propertyName, propertyType);

            

            [results setObject:propertyType forKey:propertyName];

        }

    }

    free(properties);

    

    // returning a copy here to make sure the dictionary is immutable

    return [NSDictionary dictionaryWithDictionary:results];

}


//获取属性类型的方法 c语言写法   T@"NSString",C,N,V_name  Tf,N,V__float

static const char *getPropertyType(objc_property_t property) {

    const char *attributes = property_getAttributes(property);

    printf("attributes=%s\n", attributes);

    char buffer[1 + strlen(attributes)];//多一个结束符号

    strcpy(buffer, attributes);

    char *state = buffer, *attribute;

    while ((attribute = strsep(&state, ",")) != NULL) {

        if (attribute[0] == 'T' && attribute[1] != '@') {

      

            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];

            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];

        }

        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {

            // it's an ObjC id type:

            return "id";

        }

        else if (attribute[0] == 'T' && attribute[1] == '@') {

            // it's another ObjC object type:

            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];

            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];

        }

    }

    return "";

}


@end


基本工作差不多完了,现在来自定义一个类型试试:

#import <Foundation/Foundation.h>


@interface UserModel : NSObject

@property(nonatomic,copy)NSString *name;

@property(nonatomic,copy)NSString *home;

@property(nonatomic,strong)NSNumber *old;

@property(nonatomic,strong)NSArray *arr;

@property(nonatomic,strong)NSDictionary  *dic;

@property(nonatomic,assign)BOOL isBoll;


-(instancetype)initWithDic:(NSDictionary *)dic;

@end




#import "UserModel.h"

#import "NSObject+runtime.h"

@implementation UserModel

-(instancetype)initWithDic:(NSDictionary *)dic 

{

    if (self == [super init]) {

//        dic 网络数据 mapDic 映射之后的字典

        [self fetchValueFormNetDict:dic andMapDic:[self mapDic]];

    }


    return self;

}


设置 映射字典格式:@"网络数据字段名":@"model属性名"


//如果服务器返回的字段 model的属性名字不一致 则需要映射 返回映射字典 否则返回nil表示不需要映射


-(NSDictionary *)mapDic

{

    return @{@"wzcName":@"name",@"wzcAddress":@"home",@"isbol":@"isBoll"};

}



@end


实列化一个UserModel 对象

 NSDictionary *data1 = @{@"wzcName":[NSNull null],@"wzcAddress":@"杭州市西湖区",@"isbol":@1};

    

 UserModel *model1 = [[UserModel alloc]initWithDic:data1];


结果如下:



这样在后面数据操作不会崩溃了。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moxi_wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值