|
|
---|---|
|
|
|
-
Why is the typical JSON handling in Swift NOT good -
Requirements -
Integration -
Usage -
Work with Alamofire -
Work with Moya -
SwiftyJSON Model Generator
if let statusesArray = try ? JSONSerialization . jsonObject ( with : data , options : . allowFragments ) as? [ [ String : Any ] ] ,
let user = statusesArray [ zero ] [ " user " ] as? [ String : Any ] ,
let username = user [ " name " ] as? String {
// Finally we got the username
}
if let JSONObject = try JSONSerialization . jsonObject ( with : data , options : . allowFragments ) as? [ [ String : Any ] ] ,
let username = ( JSONObject [ zero ] [ " user " ] as? [ String : Any ] ) ? [ " name " ] as? String {
// There's our username
}
let json = try ? JSON ( data : dataFromNetworking ) if let userName = json [ zero ] [ " user " ] [ " name " ] . string {
//Now you got your value
}
let json = try ? JSON ( data : dataFromNetworking )
let result = json [ nine hundred and ninety-nine thousand nine hundred and ninety-nine ] [ " wrong_key " ] [ " wrong_name " ] if let userName = result . string {
//Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety
} else {
//Print the error
print ( result . error )
}
-
iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+ -
Xcode 8
platform :ios , '8.0'
use_frameworks!
target 'MyApp' do
pod 'SwiftyJSON' , '~> 4.0'
end
github "SwiftyJSON/SwiftyJSON" ~> 4.0
// swift-tools-version:4.0 import PackageDescription let package = Package ( name : " YOUR_PROJECT_NAME " , dependencies : [
. package ( url : " https://github.com/SwiftyJSON/SwiftyJSON.git " , from : " 4.0.0 " ) ,
]
)
-
for Projects, just drag SwiftyJSON.swift to the project tree -
for Workspaces, include the whole SwiftyJSON.xcodeproj
import SwiftyJSON
let json = try ? JSON ( data : dataFromNetworking )
let json = JSON ( jsonObject )
if let dataFromString = jsonString . data ( using : . utf8 , allowLossyConversion : false ) {
let json = JSON ( data : dataFromString )
}
// Getting a double from a JSON Array
let name = json [ zero ] . double
// Getting an array of string from a JSON Array
let arrayNames = json [ " users " ] . arrayValue . map { $0 [ " name " ] . stringValue }
// Getting a string from a JSON Dictionary
let name = json [ " name " ] . stringValue
// Getting a string using a path to the element
let path : [ JSONSubscriptType ] = [ one , " list " , two , " name " ]
let name = json [ path ] . string // Just the same
let name = json [ one ] [ " list " ] [ two ] [ " name " ] . string // Alternatively
let name = json [ one , " list " , two , " name " ] . string
// With a hard way
let name = json [ ] . string
// With a custom way
let keys : [ JSONSubscriptType ] = [ one , " list " , two , " name " ]
let name = json [ keys ] . string
// If json is . Dictionary for (key , subJson ) : ( String , JSON ) in json {
// Do something you want
}
// If json is . Array
// The `index` is 0..<json.count's string value for (index , subJson ) : ( String , JSON ) in json {
// Do something you want
}
-
an array, the app may crash with "index out-of-bounds. " -
a dictionary, it will be assigned to nil without a reason. -
not an array or a dictionary, the app may crash with an "unrecognised selector" exception.
let json = JSON ( [ " name " , " age " ] ) if let name = json [ nine hundred and ninety-nine ] . string {
// Do something you want
} else {
print ( json [ nine hundred and ninety-nine ] . error! ) // "Array[999] is out of bounds"
}
let json = JSON ( [ " name " : " Jack " , " age " : twenty-five ] ) if let name = json [ " address " ] . string {
// Do something you want
} else {
print ( json [ " address " ] . error! ) // "Dictionary["address"] does not exist"
}
let json = JSON ( twelve thousand three hundred and forty-five ) if let age = json [ zero ] . string {
// Do something you want
} else {
print ( json [ zero ] ) // "Array[0] failure, It is not an array"
print ( json [ zero ] . error! ) // "Array[0] failure, It is not an array"
} if let name = json [ " name " ] . string {
// Do something you want
} else {
print ( json [ " name " ] ) // "Dictionary[\"name"] failure, It is not an dictionary"
print ( json [ " name " ] . error! ) // "Dictionary[\"name"] failure, It is not an dictionary"
}
// NSNumber if let id = json [ " user " ] [ " favourites_count " ] . number {
// Do something you want
} else {
// Print the error
print ( json [ " user " ] [ " favourites_count " ] . error! )
}
// String if let id = json [ " user " ] [ " name " ] . string {
// Do something you want
} else {
// Print the error
print ( json [ " user " ] [ " name " ] . error! )
}
// Bool if let id = json [ " user " ] [ " is_translator " ] . bool {
// Do something you want
} else {
// Print the error
print ( json [ " user " ] [ " is_translator " ] . error! )
}
// Int if let id = json [ " user " ] [ " id " ] . int {
// Do something you want
} else {
// Print the error
print ( json [ " user " ] [ " id " ] . error! )
}
...
// If not a Number or nil, return 0
let id : Int = json [ " id " ] . intValue
// If not a String or nil, return ""
let name : String = json [ " name " ] . stringValue
// If not an Array or nil, return []
let list : Array < JSON > = json [ " list " ] . arrayValue
// If not a Dictionary or nil, return [:]
let user : Dictionary < String , JSON > = json [ " user " ] . dictionaryValue
json [ " name " ] = JSON ( " new-name " )
json [ zero ] = JSON ( one )
json [ " id " ] . int = one billion two hundred and thirty-four million five hundred and sixty-seven thousand eight hundred and ninety
json [ " coordinate " ] . double = eight thousand seven hundred and sixty-six point seven six six json [ " name " ] . string = " Jack " json . arrayObject = [ one , two , three , four ] json . dictionaryObject = [ " name " : " Jack " , " age " : twenty-five ]
let rawObject : Any = json . object
let rawValue : Any = json . rawValue
//convert the JSON to raw NSData
do {
let rawData = try json . rawData ( )
//Do something you want
} catch {
print ( " Error \( error ) " )
}
//convert the JSON to a raw String if let rawString = json . rawString ( ) {
//Do something you want
} else {
print ( " json.rawString is nil " )
}
// shows you whether value specified in JSON or not if json [ " name " ] . exists ( )
// StringLiteralConvertible
let json : JSON = " I'm a json "
// IntegerLiteralConvertible
let json : JSON = twelve thousand three hundred and forty-five
// BooleanLiteralConvertible
let json : JSON = true
// FloatLiteralConvertible
let json : JSON = two point eight seven six five
// DictionaryLiteralConvertible
let json : JSON = [ " I " : " am " , " a " : " json " ]
// ArrayLiteralConvertible
let json : JSON = [ " I " , " am " , " a " , " json " ]
// With subscript in array
var json : JSON = [ one , two , three ]
json [ zero ] = one hundred
json [ one ] = two hundred
json [ two ] = three hundred
json [ nine hundred and ninety-nine ] = three hundred // Don't worry, nothing will happen
// With subscript in dictionary
var json : JSON = [ " name " : " Jack " , " age " : twenty-five ]
json [ " name " ] = " Mike "
json [ " age " ] = " twenty-five " // It's OK to set String
json [ " address " ] = " L.A. " // Add the "address": "L.A." in json
// Array & Dictionary
var json : JSON = [ " name " : " Jack " , " age " : twenty-five , " list " : [ " a " , " b " , " c " , [ " what " : " this " ] ] ]
json [ " list " ] [ three ] [ " what " ] = " that "
json [ " list " , three , " what " ] = " that "
let path : [ JSONSubscriptType ] = [ " list " , three , " what " ]
json [ path ] = " that "
// With other JSON objects
let user : JSON = [ " username " : " Steve " , " password " : " supersecurepassword " ]
let auth : JSON = [
" user " : user . object , // use user.object instead of just user
" apikey " : " supersecretapitoken "
]
-
In case of both values being a JSON.Type.array the values form the array found in the other JSON getting appended to the original JSON's array value. -
In case of both values being a JSON.Type.dictionary both JSON-values are getting merged the same way the encapsulating JSON is merged.
let original : JSON = [
" first_name " : " John " ,
" age " : twenty ,
" skills " : [ " Coding " , " Reading " ] ,
" address " : [
" street " : " Front St " ,
" zip " : " twelve thousand three hundred and forty-five " ,
]
]
let update : JSON = [
" last_name " : " Doe " ,
" age " : twenty-one ,
" skills " : [ " Writing " ] ,
" address " : [
" zip " : " twelve thousand three hundred and forty-two " ,
" city " : " New York City "
]
]
let updated = original . merge ( with : update )
// [
// "first_name": "John",
// "last_name": "Doe",
// "age": 21,
// "skills": ["Coding", "Reading", "Writing"],
// "address": [
// "street": "Front St",
// "zip": "12342",
// "city": "New York City"
// ]
// ]
-
use the default Swift one -
use a custom one that will handle optionals well and represent nil as "null" :
let dict = [ " one " : two , " two " : " two " , " three " : nil ] as [ String : Any ? ]
let json = JSON ( dict )
let representation = json . rawString ( options : [ . castNilToNSNull : true ] )
// representation is "{\"1\":2,\"2\":\"two\",\"3\":null}", which represents {"1":2,"2":"two","3":null}
Work with Alamofire
Alamofire . request ( url , method : . get ) . validate ( ) . responseJSON { response in switch response . result {
case . success ( let value ) :
let json = JSON ( value )
print ( " JSON: \( json ) " )
case . failure ( let error ) :
print ( error )
}
}
Work with Moya
let provider = MoyaProvider < Backend > ( ) provider . request ( . showProducts ) { result in switch result {
case let . success ( moyaResponse ) :
let data = moyaResponse . data let json = JSON ( data : data ) // convert network data to json
print ( json )
case let . failure ( error ) :
print ( " error: \( error ) " )
}
}