The Ultimate JSON Serialization for Swift.

Overview

PPJSONSerialization 中文介绍

Introduce

There's a library, he make everything easier, faster, and safer.

It's a library, which handles all JSON operation in one class.

As we known, the JSON result always or sometimes make our app crash, because we don't even know that JSON data is completely correct. And we have Swift now! Swift is completely strong type and type safe. So, why should we still using Objective-C and Other JSON library?

Usage

Easy Startup

  • Just add PPJSONSerialization.swift to project (I'm not planning to publish it to CocoaPods, it's a tiny library.)

  • Create your own class and subclass PPJSONSerialization

class Artist: PPJSONSerialization {
  var name: String?
  var height: Double = 0.0
}
  • Fetch data from network and create an instance of your own class
let mockString = "{\"name\": \"Pony Cui\", \"height\": 164.0}"
let artistData = Artist(JSONString: mockString)
  • Now, you can use it briefly
if let artistData = Artist(JSONString: mockString) {
  print(artistData.name)
  print(artistData.height)
}

Features

Type transfer

Remember we set height as Double in Artist Classes?

If the JSON type is in-correct, the most library will discard the result, or gives you an error message.

But PPJSONSerialization will try to convert it to Double

For example

let mockString = "{\"name\": \"Pony Cui\", \"height\": \"164.0\"}" //height is a string value
if let artistData = Artist(JSONString: mockString) {
  print(artistData.name)
  print(artistData.height) // Now it convert to Double, print 164.0
}

Type transfer now applys on string, double, int, bool

Optional value (Not stable)

The best feature in Swift is optional, PPJSONSerialization also support it.

class Artist: PPJSONSerialization {
  var name: String? // We define it as an optional value
  var height: Double = 0.0
}

let mockString = "{\"height\": \"164.0\"}"

if let artistData = Artist(JSONString: mockString) {
    if let name = artistData.name {
        print(name) // code will not execute, because the mockString doesn't contains name column.
    }
}

Null crash or Invalid JSON

Never worry about that, the failable init will gives you the opportunity deal with that. Null value will never never never set to instance.

Array Generic support

The swift array always request a generic type define, you can't store another type in it. But JSON can! That's not an easy working while we using Objective-C.

PPJSONSerialization will handle this.

For example, you define a property friends, all its member is String value.

class Artist: PPJSONSerialization {
    var name: String?
    var height: Double = 0.0
    var friends = [String]()
}

Just use it as below, note that we have 3 invalid types, but PPJSONSerialization will convert it.

let mockString = "{\"friends\": [\"Jack\", \"Leros\", \"Max\", \"LGY\", 1, 2, 3]}"

if let artistData = Artist(JSONString: mockString) {
    for friend in artistData.friends {
        print(friend)
    }
}

/*
Prints:
Jack
Leros
Max
LGY
1
2
3
*/

Dictionary Generic support

The dictionary generic is also support as Array. But I strongly recommend you use Sub-Struct to deal with Dictionary.

class Artist: PPJSONSerialization {
    var name: String?
    var height: Double = 0.0
    var friendsHeight = [String: Double]() // now we change it as dictionary
}

let mockString = "{\"friendsHeight\": {\"Jack\": 170, \"Leros\": 180, \"Max\": 168, \"LGY\": 177}}"

if let artistData = Artist(JSONString: mockString) {
    for (friend, height) in artistData.friendsHeight {
        print("\(friend), height:\(height)")
    }
}

/*
Prints:
Leros, height:180.0
Max, height:168.0
LGY, height:177.0
Jack, height:170.0
*/

Custom Type (Sub-Struct)

There's a really common situation is a dictionary contains another dictionary, you can use Dictionary Generic handle this, right? But, if you eager the model much easier to manage, or much pettier. Custom Type is really important for you.

Note: Custom Type can use in Dictionary/Array/Property either.

class Artist: PPJSONSerialization {
    var name: String?
    var height: Double = 0.0
    var friends = [ArtistFriend]()
}

// The Sub-Struct either subclasses PPJSONSerialization
class ArtistFriend: PPJSONSerialization {
    var name: String?
    var height: Double = 0.0
}

let mockString = "{\"friends\": [{\"name\": \"Jack\", \"height\": \"177.0\"}, {\"name\": \"Max\", \"height\": \"188.0\"}]}"

if let artistData = Artist(JSONString: mockString) {
    for friend in artistData.friends {
        print("\(friend.name), height:\(friend.height)")
    }
}

/*
Prints:
Optional("Jack"), height:177.0
Optional("Max"), height:188.0
*/

PPCoding

If you eager to control type transferring. Follow PPCoding protocol.

For example, we eager to transfer an timestamp(Int) to NSDate, that's a common requirement.

class CodeingStruct: PPJSONSerialization {
    var codeingDate: NSDate = NSDate() // Define a property as common, optional or non-optional available either.
}

extension NSDate: PPCoding {

    func encodeAsPPObject() -> AnyObject? {
        return timeIntervalSince1970
    }

    func decodeWithPPObject(PPObject: AnyObject) -> AnyObject? {
        if let timestamp = PPObject as? NSTimeInterval {
            return NSDate(timeIntervalSince1970: timestamp) // And now we extent NSDate
        }
        return nil
    }

}

let codingDateJSON = "{\"codeingDate\":1444885037}"

if let test = CodeingStruct(JSONString: codingDateJSON) {
    XCTAssert(test.codeingDate.description == "2015-10-15 04:57:17 +0000", "Pass")
}
  • PPCoding also support serialize operation.
  • Optional value is not available for serialize.

Array JSON

If the JSON is an array base struct. You should subclass PPJSONArraySerialization, and define a property root with generic type.

class ArrayStruct: PPJSONArraySerialization {
    var root = [Int]()
}

let arrayJSON = "[1,0,2,4]"
if let arrayObject = ArrayStruct(JSONString: arrayJSON) {
  XCTAssert(arrayObject.root.count == 4, "Pass")
  XCTAssert(arrayObject.root[0] == 1, "Pass")
  XCTAssert(arrayObject.root[1] == 0, "Pass")
  XCTAssert(arrayObject.root[2] == 2, "Pass")
  XCTAssert(arrayObject.root[3] == 4, "Pass")
}

Multiple Dimension Array

If the array contains array, it should define like this.

class MultipleDimensionArray: PPJSONSerialization {
    var twoDimension = [[Int]]()
    var threeDimension = [[[Int]]]()
}

let twoDimensionArrayJSON = "{\"twoDimension\": [[1,0,2,4], [1,0,2,4]]}"

if let test = MultipleDimensionArray(JSONString: twoDimensionArrayJSON) {
    XCTAssert(test.twoDimension[0][0] == 1, "Pass")
    XCTAssert(test.twoDimension[0][1] == 0, "Pass")
    XCTAssert(test.twoDimension[0][2] == 2, "Pass")
    XCTAssert(test.twoDimension[0][3] == 4, "Pass")
    XCTAssert(test.twoDimension[1][0] == 1, "Pass")
    XCTAssert(test.twoDimension[1][1] == 0, "Pass")
    XCTAssert(test.twoDimension[1][2] == 2, "Pass")
    XCTAssert(test.twoDimension[1][3] == 4, "Pass")
}

Key Mapping

Sometimes, network data key column is different to app's, there's relly simple way to handle this. Override the mapping method, and return a dictionary contains ["JSONKey": "PropertyKey"]

class Artist: PPJSONSerialization {
    var name: String = ""
    var height: Double = 0.0

    override func mapping() -> [String : String] {
        return ["xxxname": "name"]
    }
}

let mockString = "{\"xxxname\": \"Pony Cui\"}"

if let artistData = Artist(JSONString: mockString) {
    print(artistData.name)
}

Serialize

You use serialize to serialize PPJSONSerialization classes to JSON String or JSON Data, it's a perfect way to deliver data to server.

class Artist: PPJSONSerialization {
    var name: String = "" // Optional value is also supported.
    var height: Double = 0.0
}

let artistData = Artist()
artistData.name = "Pony Cui"
artistData.height = 164.0
let string = artistData.JSONString()
print(string)

/*
Prints: {"name":"Pony Cui","height":164}
*/

Namespace support

You may define a class wrapping classes in Swift. That's a good practice.

Here is an example, we put all PPJSONSerialization classes in DataModel namespace

class DataModel { // Struct & Enum also available

    class Artist: PPJSONSerialization {
        var name: String?
        var mainSong = Song() // Using namespace, you must init an instance. Optional type is not availabel.
        var songs = [Song()] // Using namespace, you must init an instance in array!
        var mapSong = [".": Song()] // Using namespace, you must init an instance in dictionary with any key!
    }

    class Song: PPJSONSerialization {
        var name: String?
        var duration: Double = 0.0
    }

}

let JSONString = "{\"name\": \"Pony Cui\", \"mainSong\": {\"name\":\"Love Song\", \"duration\": 168.0}, \"songs\": [{\"name\":\"Love Song\", \"duration\": 168.0}], \"mapSong\": {\"sampleKey\": {\"name\":\"Love Song\", \"duration\": 168.0}}}"

if let test = DataModel.Artist(JSONString: JSONString) {
    XCTAssert(test.name! == "Pony Cui", "Pass")
    XCTAssert(test.mainSong.name == "Love Song", "Pass")
    XCTAssert(test.mainSong.duration == 168.0, "Pass")
    XCTAssert(test.songs[0].name == "Love Song", "Pass")
    XCTAssert(test.songs[0].duration == 168.0, "Pass")
    XCTAssert(test.mapSong["sampleKey"]?.name == "Love Song", "Pass")
    XCTAssert(test.mapSong["sampleKey"]?.duration == 168.0, "Pass")
}
else {
    XCTAssert(false, "Failed")
}
  • Multiple level nampspace is available.

Sub-Class

You can subclass your struct, it's okey.

class CommonResponse: PPJSONSerialization {
    var error: String?
}

class ArtistResponse: CommonResponse {
    // ...
}

PPJSONSerialization is still in development, welcome to improve the project together.

Requirements

  • iOS 7.0+ / Mac OS X 10.10+
  • Xcode 7.0
  • Swift 2.0

Integration

Add PPJSONSerialization.swift into your project, that's enough

License

MIT License, Please feel free to use it.

Thanks

  • Thanks for @onevcat suggest use Failable init.
  • Thanks for @neil-wu using and reported issues.
Comments
  • How to define a nested array(multidimensional array) with Double type?

    How to define a nested array(multidimensional array) with Double type?

    In my project,I need to define a multidimensional array, like this:

    let jsonstr: String = "{ \"Type\": \"Polygon\", \"ValueList\": [ [30.2],[10.5] ] }"
    
    class AreaArrayObj: PPJSONSerialization {
        var Type: String = ""
        var ValueList: [ [Double] ] = [[0.0]]
    }
    

    It seems that the ValueList is always empty array.

    tplObject.copy() as? PPJSONSerialization is nil

    opened by neil-wu 9
  • Int64 value can not be parsed

    Int64 value can not be parsed

    (Well, I come back again)

    Test case:

    let jsonstr: String = "{ \"Val\": 111 }"
    
    class AreaArrayObj: PPJSONSerialization {
        var Val: Int64 = 0
    }
    
    
    opened by neil-wu 2
  • Why the array must define a default value?

    Why the array must define a default value?

    The wiki shows that we can define array like this:

    // BuildingStruct
    class BuildingStruct: PPJSONSerialization {
        var buildNumber = ""
        var managementRoom = RoomStruct()
        var buildRooms = [RoomStruct()] //have a default value
    }
    

    If I define it as followings, it will fail.

    // BuildingStruct
    class BuildingStruct: PPJSONSerialization {
        var buildNumber = ""
        var managementRoom = RoomStruct()
        var buildRooms: [RoomStruct] = [] //????
    }
    
    opened by neil-wu 2
  • fix compile warning on xcode7 (7A218)

    fix compile warning on xcode7 (7A218)

    fix compile warning on xcode7 (7A218): PPJSONSerialization.swift:189:28: Immutable value 'propertyArray' was never used; consider replacing with '_' or removing it

    opened by neil-wu 0
  • option a.jsonString didWork

    option a.jsonString didWork

    class Model: PPJSONSerialization { var a: Int? = 0 var b: Int = 0 var c: Int? override init() { super.init() } }

    only Model.b can transfer for json string

    opened by zhaoyunyi 0
  • Mappy of [AnyObject]() does not work.

    Mappy of [AnyObject]() does not work.

    I have a json where am array can be either, [String] or [Dictionary], so i decided to use [AnyObject], but PPJSONSerialization fails to map and the array has always 0 values. Can someone please guide me on this.

    below is the json

    {
      "assetfields": [
        {
          "text": "Invoice Files",
          "value": [
            {
              "name": "agri.png",
              "fileid": 560,
              "url": "/tpfileservlet?fileID=560&mode=assetfieldfile"
            },
            {
              "name": "bingo-logo.png",
              "fileid": 559,
              "url": "/tpfileservlet?fileID=559&mode=assetfieldfile"
            }
          ],
          "assetfieldid": 111,
          "type": "File Upload"
        },
        {
          "text": "upccode",
          "value": [
            "upccode111111111"
          ],
          "assetfieldid": 110,
          "type": "Text"
        },
        {
          "text": "Installation Date",
          "value": [
            "Mar 31 2016",
            "00:00"
          ],
          "assetfieldid": 109,
          "type": "Date / Time"
        },
        {
          "text": "Serial Number",
          "value": [
            "123"
          ],
          "assetfieldid": 104,
          "type": "Text"
        }
      ],
      "assetclassid": 75,
      "name": "Lenovo Laptop",
      "assetsubclassid": 75,
      "assetfamilyid": 73,
      "assetid": 115
    }
    

    and my class is

    class AssetField: PPJSONSerialization {
        var text: String?
        var type: String?
        var assetfieldid: NSNumber?
        var value = [AnyObject]()
    }
    
    
    opened by bonniejaiswal 0
Owner
PonyCui
The SVGA / MPFlutter project founder.
PonyCui
Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very important part of Pitaya.

John Lui 454 Oct 30, 2022
Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs

Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs.

Julio Cesar Guzman Villanueva 2 Oct 6, 2022
Implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top of Swift's Codable implementations.

DynamicCodableKit DynamicCodableKit helps you to implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top

SwiftyLab 15 Oct 16, 2022
AlamofireObjectMappe - An Alamofire extension which converts JSON response data into swift objects using ObjectMapper

AlamofireObjectMapper An extension to Alamofire which automatically converts JSON response data into swift objects using ObjectMapper. Usage Given a U

Tristan Himmelman 2.6k Dec 29, 2022
Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable

Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable. Elevate should no longer be used for

Nike Inc. 611 Oct 23, 2022
Freddy - A reusable framework for parsing JSON in Swift.

Why Freddy? Parsing JSON elegantly and safely can be hard, but Freddy is here to help. Freddy is a reusable framework for parsing JSON in Swift. It ha

Big Nerd Ranch 1.1k Jan 1, 2023
[Deprecated] A shiny JSON parsing library in Swift :sparkles: Loved by many from 2015-2021

?? Deprecation Notice ?? Gloss has been deprecated in favor of Swift's Codable framework. The existing Gloss source is not going away, however updates

Harlan Kellaway 1.6k Nov 24, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
Himotoki (紐解き) is a type-safe JSON decoding library written purely in Swift.

Himotoki Himotoki (紐解き) is a type-safe JSON decoding library written purely in Swift. This library is highly inspired by the popular Swift JSON parsin

IKEDA Sho 799 Dec 6, 2022
JASON is a faster JSON deserializer written in Swift.

JASON is a faster JSON deserializer written in Swift. JASON is the best framework we found to manage JSON at Swapcard. This is by far the fastest and

Damien 1k Oct 15, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
PMJSON provides a pure-Swift strongly-typed JSON encoder/decoder

Now Archived and Forked PMJSON will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork of PMJS

Postmates Inc. 364 Sep 28, 2022
SwiftyJSON makes it easy to deal with JSON data in Swift.

SwiftyJSON SwiftyJSON makes it easy to deal with JSON data in Swift. Platform Build Status *OS Linux Why is the typical JSON handling in Swift NOT goo

SwiftyJSON 21.7k Jan 3, 2023
macOS app to generate Swift 5 code for models from JSON (with Codeable)

SwiftyJSONAccelerator - MacOS app Codeable Model file Generator For Swift 5 Version v2.2 Generate initializer function for classes Application Downloa

Karthikeya Udupa 929 Dec 6, 2022
The easy to use Swift JSON decoder

Unbox is deprecated in favor of Swift’s built-in Codable API and the Codextended project. All current users are highly encouraged to migrate to Codable as soon as possible.

John Sundell 2k Dec 31, 2022