Object to Json (for parent classes and arrays)

Links to the original text: https://my.oschina.net/youtk21ai/blog/540708

Original address: http://www.pluto-y.com/object-to-json/

This article is aimed at friends who do not want to use third-party frameworks but want to convert OC to Json.
There is a lot of information about the conversion from OC to Json, but there are still some shortcomings in the conversion. The shortcomings will also be mentioned in the next article. But first, let's look at the implementation methods and implementations that we often see on the network, and fill in the defects one by one.

First look at the implementation of the network

At the beginning of the project, I didn't want to use the third-party framework for the time being, so I searched for the information about how OC can be transferred to Json. When I started to use OC, I realized it mainly through the following methods.

The first method is the following. This method is used to traverse attributes in objects and convert them into NSDictionary.

+ (NSDictionary*)getObjectData:(id)obj {

    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    unsigned int propsCount;
    objc_property_t *props = class_copyPropertyList([obj class], &propsCount);
    for(int i = 0;i < propsCount; i++)
    {
        objc_property_t prop = props[i];
        NSString *propName = [NSString stringWithUTF8String:property_getName(prop)];
        id value = [obj valueForKey:propName];
        if(value == nil)
        {
            value = [NSNull null];
            continue;
        }
        else
        {
            value = [self getObjectInternal:value];
        }
        [dic setObject:value forKey:propName];
    }
    return dic;

}

Next is the following method, which obviously means that the value of each attribute is changed and stored in NSDictionary in the form of key: value.

+(id)getObjectInternal:(id)obj {
    if([obj isKindOfClass:[NSString class]]
       || [obj isKindOfClass:[NSNumber class]]
       || [obj isKindOfClass:[NSNull class]])
    {
        return obj;
    }
    if([obj isKindOfClass:[NSArray class]])
    {
        NSArray *objarr = obj;
        NSMutableArray *arr = [NSMutableArray arrayWithCapacity:objarr.count];
        for(int i = 0;i < objarr.count; i++)
        {
            [arr setObject:[self getObjectInternal:[objarr objectAtIndex:i]] atIndexedSubscript:i];
        }
        return arr;
    }
    if([obj isKindOfClass:[NSDictionary class]])
    {
        NSDictionary *objdic = obj;
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[objdic count]];
        for(NSString *key in objdic.allKeys)
        {
            [dic setObject:[self getObjectInternal:[objdic objectForKey:key]] forKey:key];
        }
        return dic;
    }
    return [self getObjectData:obj];
}

Finally, just go through the data WithJSONObject: options: error: in the language-objectivec NSJSONSerialization you all know. The code is as follows:

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self getObjectData:obj] options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

Is the parent property missing?

In the process of using, it seems that the parent property can not be transferred, and the parent property can not be found in the Json of the transformation. So I started looking at getObjectData: this method. Just make a slight modification to this method. See below after specific modification:

+ (NSDictionary*)getObjectData:(id)obj {
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    unsigned int propsCount;
    Class class = [obj class];
    do { // This do-while is added to traverse the property pages of the parent class
        objc_property_t *props = class_copyPropertyList(class, &propsCount);
        for(int i = 0;i < propsCount; i++)
        {
            objc_property_t prop = props[i];

            NSString *propName = [NSString stringWithUTF8String:property_getName(prop)];
            id value = [obj valueForKey:propName];
            if(value == nil)
            {
                value = [NSNull null];
                continue;
            }
            else
            {
                value = [self getObjectInternal:value];
            }
            [dic setObject:value forKey:propName];
        }
        class = [class superclass];
    } while (class != [NSObject class]);
    return dic;
}

The main purpose is to add a do-while statement, which is mainly used to traverse variables in the parent class until the parent class of the traversed class is NSObject. In this way, the attributes of the parent class can be traversed.

Can an array (NSArray) be converted to Json?

After using it for a period of time, we found that the array could not be transferred to Json, and there would always be a situation that could not be transferred to Json, so we had to see if the previous method had been improved. Later, it was found that it was only necessary to traverse NSArray once and add [,]. Then I encapsulated NSData into NSString as follows:

+(NSString *)getJSONString:(id)obj {
    NSString *jsonString;
    NSData *jsonData;
    if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSMutableArray class]]) {
        NSString *tmpJson;
        jsonString = @"[";
        for (id object in obj) {
            tmpJson = [self getJSONString:object];
            jsonString = [NSString stringWithFormat:@"%@%@,", jsonString, tmpJson];
        }
        jsonString = [[jsonString substringToIndex:jsonString.length-1] stringByAppendingString:@"]"];
    } else {
        jsonData = [self getJSONData:obj];
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    return jsonString;
}

Finally, we can have fun.

Reprinted in: https://my.oschina.net/youtk21ai/blog/540708

Tags: JSON network encoding Attribute

Posted on Fri, 13 Sep 2019 07:45:44 -0700 by rashmi_k28