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

来源:互联网 发布:通关宝典 软件 编辑:程序博客网 时间:2024/05/17 00:08

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

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

[selfsetValue: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 = [selfgetAllProperties];

   //需要映射

   if (MapDic !=nil) {

        

       NSArray *allKeys = dic.allKeys;

        

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

        

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

            

           NSString *key = allKeys[i];

            

            [temDicsetObject:dic[key]forKey:MapDic[key]];

        }

        

       //遍历属性数组

       for (NSString *key in properties) {

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

            [selfsetValue:temDic[key]forKeyPath:key];

        }


    }

   else//不需要映射

    {

       

       //遍历属性数组

       for (NSString *key in properties) {

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

            [selfsetValue:dic[key]forKeyPath:key];

        }


    }

   //null或者 nil处理

    [selfnullDeal];

    

}


//获取所有的属性名

- (NSArray *)getAllProperties

{

   u_int count;

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

   NSMutableArray *propertiesArray = [NSMutableArrayarrayWithCapacity:count];

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

    {

       constchar* propertyName =property_getName(properties[i]);

        [propertiesArrayaddObject: [NSStringstringWithUTF8String: propertyName]];

    }

   free(properties);

   return propertiesArray;

}


-(void)nullDeal

{

    //找到属性对应的类型

   NSDictionary *typeDic = [selfclassPropsFor:[selfclass]];

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

    

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


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

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

        

       if ([[selfvalueForKey:arr[i]]isKindOfClass:[NSNullclass]] || [selfvalueForKey:arr[i]] ==nil) {

            

           if ([typeStringisEqualToString:@"NSArray"]) {

                

                [selfsetValue:@[]forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"NSString"]) {

                

                [selfsetValue:@""forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"NSNumber"]) {

                

                [selfsetValue:@0forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"NSDictionary"]) {

                

                [selfsetValue:@{}forKey:arr[i]];

            }

            

           if ([typeStringisEqualToString:@"B"]) {

                

                [selfsetValue:0forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"f"]) {

                

                [selfsetValue:0forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"d"]) {

                

                [selfsetValue:0forKey:arr[i]];

            }

           if ([typeStringisEqualToString:@"i"]) {

                

                [selfsetValue:0forKey:arr[i]];

            }

        }

    }

    

   

    

}


//获取属性名称数组

- (NSDictionary *)classPropsFor:(Class)klass

{

   if (klass ==NULL) {

       returnnil;

    }

    

   NSMutableDictionary *results = [[NSMutableDictionaryalloc]init];

    

   unsignedint outCount, i;

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

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

       objc_property_t property = properties[i];

       constchar *propName =property_getName(property);

       if(propName) {

            

           constchar *propType =getPropertyType(property);

           NSString *propertyName = [NSStringstringWithUTF8String:propName];

           NSString *propertyType = [NSStringstringWithUTF8String:propType];

            

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

            

            [resultssetObject:propertyTypeforKey:propertyName];

        }

    }

   free(properties);

    

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

   return [NSDictionarydictionaryWithDictionary:results];

}


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

staticconstchar *getPropertyType(objc_property_t property) {

   constchar *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 = [[NSStringalloc]initWithBytes:attribute +1length:strlen(attribute) - 1encoding:NSASCIIStringEncoding];

           return (constchar *)[namecStringUsingEncoding:NSASCIIStringEncoding];

        }

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

           // it's an ObjC id type:

           return"id";

        }

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

           // it's another ObjC object type:

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

           return (constchar *)[namecStringUsingEncoding: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 == [superinit]) {

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

        [selffetchValueFormNetDict:dicandMapDic:[selfmapDic]];

    }


   returnself;

}


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


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


-(NSDictionary *)mapDic

{

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

}



@end


实列化一个UserModel对象

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

    

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


结果如下:



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


1 0
原创粉丝点击