Latest 1.0.0
Homepage https://github.com/tonyzp/TypedJSON
License MIT
Platforms ios 8.0
Authors

CI Status
Version
License
Platform

The way we handle Objective-C JSON dictionary is Ugly.

Objective-C is a runtime, weakly typed language. The NSDictionary class in Objective-C isn’t a type-safe object.

Suppose we have a json dictionary:

NSDictionary *json = @{ @"username": @"tp", @"password": @"123456", @"scores": @{ @"programming": @70, @"language": @80 }, @"tels": @[ @"1367890876", @"02884435261" ] };

We may access the dictionary in this way:

NSString *username = json[@"username"];

if (!username || ![username isKindOfClass:NSString.class] || username.length == 0) {
    return;
}

// Do something with username string

or:

NSDictionary *scores = json[@"scores"];

if (!scores || ![scores isKindOfClass:NSDictionary.class] || scores.count == 0) {
    return;
}

NSNumber *score = scores[@"programming"];

if (!score || ![score isKindOfClass:NSNumber.class]) {
    return;
}

// Do something with programming score number

The problem here is, we do much things with type & value check to insure type-safety, these make our code ugly.

A better way to handle this

With TypedJSON, we use chain operators to solve this problem in a semantic way. These try to insure the elegance and readability of the code.

NSString *username = json.tj.string(@"username").without.empty.value;

if (!username) {
    return;
}

// Do something with username string

and:

NSNumber *score = json.tj.dictionary(@"scores").number(@"programming").value;

if (!score) {
    return;
}

// Do something with programming score number

More example

The json data in this example:

{
    "username": "tp",
    "password": "123456",
    "scores": {
        "programming": 70,
        "language": 80
    },
    "tels": [
        "+8613612345678",
        "028-84555555"
    ]
}

How we access this json dictionary with TypedJSON:

NSDictionary *json = [self loadJSON];

// Get username from json exclued empty string value '', return 'anonymous' while nil.
NSString *username = json.tj.string(@"username").without.empty.defaults(@"anonymous").value;

// Get programming score number in scores dictionary from json.
NSNumber *programmingScore = json.tj.dictionary(@"scores").number(@"programming").value;

// Get politics score number in scores dictionary from json, return 0 while politics do not exists.
NSNumber *politicsScore = json.tj.dictionary(@"scores").number(@"politics").with.defaults(@0).value;

NSLog(@"The programming score of %@ is %@, and politics %@.", username, programmingScore, politicsScore);

Installation

TypedJSON is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'TypedJSON'

Then run pod install to integrate.

Usage

To import TypedJSON, you just:

#import <TypedJSON/TypedJSON.h>

Read value in dictionary with type safety

Read string in dictionary with a specified key:

json.tj.string(@"foo").value;

The value could be nil while it’s not a NSString type.

Read number in dictionary with a specified key:

json.tj.number(@"foo").value;

The value could be nil while it’s not a NSNumber type.

Read array in dictionary with a specified key:

json.tj.array(@"foo").value;

The value could be nil while it’s not a NSArray type.

Read dictionary in dictionary with a specified key:

json.tj.dictionary(@"foo").value;

The value could be nil while it’s not a NSDictionary type.

Insure not empty

Sometimes we get empty value in ditionary, such as:

  • empty string: ""
  • empty array: @[]
  • empty dictionary: @{}

Use - empty operator to ignore them:

json.tj.string(@"foo").without.empty.value;

Return nil if the value of "foo" is a ""

json.tj.array(@"foo").without.empty.value;

Return nil if the value of "foo" is a @[]

json.tj.dictionary(@"foo").without.empty.value;

Return nil if the value of "foo" is a @{}

Provide default value while get nil

Suppose we get nil value in the chain, and we need to provide a default value:

json.tj.string(@"foo").with.defaults(@"bar").value;

The - with operator could be omitted, it just to insure semantics of the statment.

The - any operator

This operator just get value by a specified key, without type check:

json.tj.any(@"foo").value;

The return value is an id type.

Or you could use Valuable extension to do the type check:

json.tj.any(@"foo").stringValue;

- stringValue will make sure the return value matches NSString type, if not then return nil.

Access values in a chain

Supporse the value is wrapped in the inner dictionary:

{
    "foo": {
        "bar": {
            "greeting": "Hello ~"
        }
    }
}

We can access the greeting in a chain:

json.tj.dictionary(@"foo").dictionary(@"bar").string(@"greeting").value;

The - find operator

In the example above we access greeting in an operator chain, with - find operator we can change the code:

json.tj.find(@"greeting").value;

- find operator enumerate the dictionary recursively to get the value mathes the specified key, but doesn’t do the type check. In order to insure type-safety, we could use Valuable extension method - stringValue:

json.tj.find(@"greeting").stringValue;

The - as operator

This operator is similar to Valuable extension methods. It make sure the value matches the specified class type. Usually we use this operator after - find or - any operators in the operator chain:

json.tj.find(@"greeting").as(NSString.class).value;

This make sure the result value of - find operator @"greeting" matches NSString class.

It”s equal to:

json.tj.find(@"greeting").stringValue;

Author

tp, [email protected]

License

TypedJSON is available under the MIT license. See the LICENSE file for more info.

Latest podspec

{
    "name": "TypedJSON",
    "version": "1.0.0",
    "summary": "A type safe way to access value in Objective-c JSON dictionary.",
    "description": "A type safe way to access value in Objective-c JSON dictionary.",
    "homepage": "https://github.com/tonyzp/TypedJSON",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "tp": "[email protected]"
    },
    "source": {
        "git": "https://github.com/tonyzp/TypedJSON.git",
        "tag": "1.0.0"
    },
    "platforms": {
        "ios": "8.0"
    },
    "source_files": "TypedJSON/Classes/**/*.{h,m}",
    "public_header_files": "TypedJSON/Classes/**/*.h",
    "testspecs": [
        {
            "name": "Tests",
            "test_type": "unit",
            "source_files": "TypedJSON/Tests/**/*.{h,m}",
            "dependencies": {
                "Kiwi": []
            }
        }
    ]
}

Pin It on Pinterest

Share This