SlideShare a Scribd company logo
Hi, I’m Donny.
I build iOS apps.
Hi, I’m Donny.
I build iOS apps.
JSON and Swift…
JSON and Swift…
Still A Better Love Story Than Twilight
Topics
• Pre-Swift 4.0 JSON handling

• Some things I learned about JSON pre-Swift 4.0

• Handling JSON in Swift 4.0

• Concluding remarks
Pre-Swift 4.0 JSON Handling
{
"items": [{
"line_up": [{
"artist": {
"name": "Foo"
}
}]
}]
}
JSON File:
Pre-Swift 4.0 JSON Handling
{
"items": [{
"line_up": [{
"artist": {
"name": "Foo"
}
}]
}]
}
JSON File: Swift 1.0:
if let items = json["items"] as? [[String: AnyObject]] {
if let firstItem = items.first {
if let item = firstItem as? [String: AnyObject] {
if let lineUp = item["line_up"] as? [[String: AnyObject]] {
if let firstLineupItem = lineUp.first {
if let artist = firstLineupItem["artist"] as? [String: AnyObject] {
if let name = artist["name"] as? String {
print(name)
}
}
}
}
}
}
}
Pre-Swift 4.0 JSON Handling
{
"items": [{
"line_up": [{
"artist": {
"name": "Foo"
}
}]
}]
}
JSON File: Swift 2.0:
guard let items = json["items"] as? [String: Any],
let firstItem = items.first,
let item = firstItem as? [String: Any],
let lineUp = firstItem["line_up"] as? [[String: Any]],
let firstLineUpItem = lineUp.first,
let artist = firstLineUpItem["artist"] as? [String: Any],
let name = artist["name"] as? String
else { return }
print(name)
Pre-Swift 4.0 JSON Handling
{
"items": [{
"line_up": [{
"artist": {
"name": "Foo"
}
}]
}]
}
JSON File: SwiftyJSON
guard let item = json["items"].arrayValue.first,
let lineUpItem = item["line_up"].arrayValue.first,
let name = lineUpItem["artist"]["name"].string
else { return }
print(name)
SwiftyJSON is amazing!
guard let item = json["items"].arrayValue.first,
let lineUpItem = item["line_up"].arrayValue.first,
let name = lineUpItem["artist"]["name"].string
else { return }
print(name)
😍
SwiftyJSON is amazing!
guard let item = json["items"].arrayValue.first,
let lineUpItem = item["line_up"].arrayValue.first,
let name = lineUpItem["artist"]["name"].string
else { return }
print(name)
😍
A performance test
A performance test
{ id: 260,
name: 'DAS Foute Oktoberfest 20171',
start: '2017-02-20T16:00:00+0000',
end: '2017-10-07T23:59:00+0000',
publish_from: '2016-11-09T08:00:00+0000',
publish_to: '2017-10-07T23:59:00+0000',
categories: [ { id: 2, name: 'NAME GOES HERE' } ],
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4!
1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532',
email: 'random@email.com',
id: 169,
radius: 500 },
line_up:
[ { id: 1, name: 'nino' },
{ id: 2, name: 'lisa' },
{ id: 7, name: 'kees' },
{ id: 4, name: 'Rodney' },
{ id: 8, name: 'Oscar' },
{ id: 9, name: 'Dick' } ],
description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen.
rnrnBinnenkort meer info!',
image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' }
A performance test
{ id: 260,
name: 'DAS Foute Oktoberfest 20171',
start: '2017-02-20T16:00:00+0000',
end: '2017-10-07T23:59:00+0000',
publish_from: '2016-11-09T08:00:00+0000',
publish_to: '2017-10-07T23:59:00+0000',
categories: [ { id: 2, name: 'NAME GOES HERE' } ],
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4!
1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532',
email: 'random@email.com',
id: 169,
radius: 500 },
line_up:
[ { id: 1, name: 'nino' },
{ id: 2, name: 'lisa' },
{ id: 7, name: 'kees' },
{ id: 4, name: 'Rodney' },
{ id: 8, name: 'Oscar' },
{ id: 9, name: 'Dick' } ],
description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen.
rnrnBinnenkort meer info!',
image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' }
• 2080 events
A performance test
{ id: 260,
name: 'DAS Foute Oktoberfest 20171',
start: '2017-02-20T16:00:00+0000',
end: '2017-10-07T23:59:00+0000',
publish_from: '2016-11-09T08:00:00+0000',
publish_to: '2017-10-07T23:59:00+0000',
categories: [ { id: 2, name: 'NAME GOES HERE' } ],
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4!
1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532',
email: 'random@email.com',
id: 169,
radius: 500 },
line_up:
[ { id: 1, name: 'nino' },
{ id: 2, name: 'lisa' },
{ id: 7, name: 'kees' },
{ id: 4, name: 'Rodney' },
{ id: 8, name: 'Oscar' },
{ id: 9, name: 'Dick' } ],
description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen.
rnrnBinnenkort meer info!',
image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' }
• 2080 events
• Nested objects
A performance test
{ id: 260,
name: 'DAS Foute Oktoberfest 20171',
start: '2017-02-20T16:00:00+0000',
end: '2017-10-07T23:59:00+0000',
publish_from: '2016-11-09T08:00:00+0000',
publish_to: '2017-10-07T23:59:00+0000',
categories: [ { id: 2, name: 'NAME GOES HERE' } ],
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4!
1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532',
email: 'random@email.com',
id: 169,
radius: 500 },
line_up:
[ { id: 1, name: 'nino' },
{ id: 2, name: 'lisa' },
{ id: 7, name: 'kees' },
{ id: 4, name: 'Rodney' },
{ id: 8, name: 'Oscar' },
{ id: 9, name: 'Dick' } ],
description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen.
rnrnBinnenkort meer info!',
image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' }
• 2080 events
• Nested objects
• Tested on iPhone 5c
A performance test
A performance test
func loadSwifty() {
guard let data = getFileData()
else { return }
let jsonFile = JSON(data: data)
for eventJSON in jsonFile["events"].arrayValue {
let location = Location(id: eventJSON["location"]["id"].intValue,
name: eventJSON["location"]["name"].stringValue,
lat: eventJSON["location"]["latitude"].double,
lon: eventJSON[“location"]["longitude"].double,
address: eventJSON["location"]["address"].stringValue,
zipcode: eventJSON[“location"]["zipcode"].stringValue)
// etc.
}
showCompletion()
}
A performance test
func loadSwifty() {
guard let data = getFileData()
else { return }
let jsonFile = JSON(data: data)
for eventJSON in jsonFile["events"].arrayValue {
let location = Location(id: eventJSON["location"]["id"].intValue,
name: eventJSON["location"]["name"].stringValue,
lat: eventJSON["location"]["latitude"].double,
lon: eventJSON[“location"]["longitude"].double,
address: eventJSON["location"]["address"].stringValue,
zipcode: eventJSON[“location"]["zipcode"].stringValue)
// etc.
}
showCompletion()
}
6.76 seconds to complete
A performance test
func loadSwifty() {
guard let data = getFileData()
else { return }
let jsonFile = JSON(data: data)
for eventJSON in jsonFile["events"].arrayValue {
let location = Location(id: eventJSON["location"]["id"].intValue,
name: eventJSON["location"]["name"].stringValue,
lat: eventJSON["location"]["latitude"].double,
lon: eventJSON[“location"]["longitude"].double,
address: eventJSON["location"]["address"].stringValue,
zipcode: eventJSON[“location"]["zipcode"].stringValue)
// etc.
}
showCompletion()
}
6.76 seconds to complete
"😭
A performance test
A performance test
func loadNormal() {
guard let data = getFileData(),
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
let json = jsonObject as? DWJSON,
let events = json["events"] as? [DWJSON]
else { return }
for eventJSON in events {
guard let locationJSON = eventJSON["location"] as? DWJSON,
let categoriesJSON = eventJSON["categories"] as? [DWJSON],
let lineUpJSON = eventJSON["line_up"] as? [DWJSON]
else { return }
// etc.
}
showCompletion()
}
A performance test
func loadNormal() {
guard let data = getFileData(),
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
let json = jsonObject as? DWJSON,
let events = json["events"] as? [DWJSON]
else { return }
for eventJSON in events {
guard let locationJSON = eventJSON["location"] as? DWJSON,
let categoriesJSON = eventJSON["categories"] as? [DWJSON],
let lineUpJSON = eventJSON["line_up"] as? [DWJSON]
else { return }
// etc.
}
showCompletion()
}
1.84 seconds to complete
A performance test
func loadNormal() {
guard let data = getFileData(),
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
let json = jsonObject as? DWJSON,
let events = json["events"] as? [DWJSON]
else { return }
for eventJSON in events {
guard let locationJSON = eventJSON["location"] as? DWJSON,
let categoriesJSON = eventJSON["categories"] as? [DWJSON],
let lineUpJSON = eventJSON["line_up"] as? [DWJSON]
else { return }
// etc.
}
showCompletion()
}
1.84 seconds to complete
$😍
What did I learn?
What did I learn?
• Be careful about libraries that make things easy; they might be (very) slow.
What did I learn?
• Be careful about libraries that make things easy; they might be (very) slow.
• Sometimes uglier code is faster (unfortunately).
What did I learn?
• Be careful about libraries that make things easy; they might be (very) slow.
• Sometimes uglier code is faster (unfortunately).
• Working with JSON isn’t as bad as it seems in Swift 2.0+.
What about Swift 4.0?
❓&❓
Introducing Codable
Introducing Codable
struct Category {
let id: Int
let name: String
}
let category = Category(id: categoryJSON["id"] as? Int ?? 0,
name: categoryJSON["name"] as? String ?? "")
< Swift 4.0
Introducing Codable
struct Category {
let id: Int
let name: String
}
let category = Category(id: categoryJSON["id"] as? Int ?? 0,
name: categoryJSON["name"] as? String ?? "")
< Swift 4.0
struct Category: Codable {
let id: Int
let name: String
}
Swift 4.0
let decoder = JSONDecoder()
let category = try? decoder.decode(Category.self, from: data)
Introducing Codable
struct Category {
let id: Int
let name: String
}
let category = Category(id: categoryJSON["id"] as? Int ?? 0,
name: categoryJSON["name"] as? String ?? "")
< Swift 4.0
struct Category: Codable {
let id: Int
let name: String
}
Swift 4.0
let decoder = JSONDecoder()
let category = try? decoder.decode(Category.self, from: data)
Property names are directly mapped to JSON keys
Introducing Codable
But what if the keys don’t match?
Introducing Codable
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: ‘https://www.google.nl/',
email: 'random@email.com',
id: 169,
radius: 500 }
But what if the keys don’t match?
Introducing Codable
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: ‘https://www.google.nl/',
email: 'random@email.com',
id: 169,
radius: 500 }
But what if the keys don’t match?
Introducing Codable
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: ‘https://www.google.nl/',
email: 'random@email.com',
id: 169,
radius: 500 }
struct Location {
let id: Int
let name: String
let lat: Double?
let lon: Double?
let address: String
let zipcode: String
}
But what if the keys don’t match?
Introducing Codable
location:
{ name: 'Goffertpark, Nijmegen (NL)',
address: '',
zipcode: '1234AB',
city: 'Nijmegen',
state: 'Noord-whateverland',
country: 'NL',
latitude: 51.82548,
longitude: 5.836629,
url: ‘https://www.google.nl/',
email: 'random@email.com',
id: 169,
radius: 500 }
struct Location: Codable {
enum CodingKeys: String, CodingKey {
case id, name, address, zipcode
case lat = "latitude"
case lon = "longitude"
}
let id: Int
let name: String
let lat: Double?
let lon: Double?
let address: String
let zipcode: String
}
But what if the keys don’t match?
Codable Performance
Codable Performance
func loadCodable() {
guard let data = getFileData()
else { return }
do {
let decoder = JSONDecoder()
let eventsResponse = try decoder.decode(EventsResponse.self, from: data)
showCompletion()
} catch {
print(error)
}
}
Codable Performance
func loadCodable() {
guard let data = getFileData()
else { return }
do {
let decoder = JSONDecoder()
let eventsResponse = try decoder.decode(EventsResponse.self, from: data)
showCompletion()
} catch {
print(error)
}
}
1.82 seconds to complete
Codable Performance
func loadCodable() {
guard let data = getFileData()
else { return }
do {
let decoder = JSONDecoder()
let eventsResponse = try decoder.decode(EventsResponse.self, from: data)
showCompletion()
} catch {
print(error)
}
}
1.82 seconds to complete
$😍
Codable and Date
struct DWDate: Codable {
let date: Date?
}
let jsonString = "{"date": "31-08-2017 +0000"}"
let json = jsonString.data(using: .utf8)!
do {
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy Z"
decoder.dateDecodingStrategy = .formatted(formatter)
let response = try decoder.decode(DWDate.self, from: json)
} catch {
print(error)
}
Codable and Date
struct DWDate: Codable {
let date: Date?
}
let jsonString = "{"date": ""}" //' ' '
let json = jsonString.data(using: .utf8)!
do {
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy Z"
decoder.dateDecodingStrategy = .formatted(formatter)
let response = try decoder.decode(DWDate.self, from: json)
} catch {
print(error)
}
Codable and Date
struct DWDate: Codable {
let date: Date?
}
let jsonString = "{"date": ""}" //' ' '
let json = jsonString.data(using: .utf8)!
do {
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy Z"
decoder.dateDecodingStrategy = .formatted(formatter)
let response = try decoder.decode(DWDate.self, from: json)
} catch {
print(error)
}
dataCorrupted(Swift.DecodingError.Context(codingPath:
[__lldb_expr_156.DWDate.(CodingKeys in
_995AD5D014A8F9E1965F4BEEB81F4E38).date], debugDescription: "Date
string does not match format expected by formatter.", underlyingError: nil))
Codable and Date
struct DWDate: Codable {
let date: Date?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.date = try? container.decode(Date.self, forKey: .date)
}
}
What else should you know?
struct Prize: Codable {
enum PrizeType: Int, Codable {
case ticket = 1, voucher = 2
}
let name: String
let type: PrizeType
}
{
"name" : "Test",
"type" : 1
}
What else should you know?
let prize = Prize(name: "Test", type: .ticket)
let encoder = JSONEncoder()
let result = try! encoder.encode(prize)
{
"name" : "Test",
"type" : 1
}
What else should you know?
struct EventsResponse: Codable {
let events: [Event]
}
let eventsResponse = try decoder.decode([String: [Event]].self, from: data)
let eventsResponse = try decoder.decode(EventsResponse.self, from: data)
Concluding remarks
Concluding remarks
• Handling JSON with libraries can be convenient yet slow
Concluding remarks
• Handling JSON with libraries can be convenient yet slow
• The Codable protocol performs really well
Concluding remarks
• Handling JSON with libraries can be convenient yet slow
• The Codable protocol performs really well
• Optional date handling is a bit too strict IMO
Concluding remarks
• Handling JSON with libraries can be convenient yet slow
• The Codable protocol performs really well
• Optional date handling is a bit too strict IMO
• You can do really powerful things with Codable
Concluding remarks
• Handling JSON with libraries can be convenient yet slow
• The Codable protocol performs really well
• Optional date handling is a bit too strict IMO
• You can do really powerful things with Codable
http://benscheirman.com/2017/06/ultimate-guide-to-json-parsing-with-swift-4/
Thanks!

More Related Content

What's hot

PostgreSQL Open SV 2018
PostgreSQL Open SV 2018PostgreSQL Open SV 2018
PostgreSQL Open SV 2018artgillespie
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
jQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20PresentationjQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20Presentationguestcf600a
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserDan Jenkins
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETTomas Jansson
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsIgnacio Martín
 
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Remy Sharp
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityRyan Weaver
 
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingBDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingJohn Ferguson Smart Limited
 
The Ring programming language version 1.5.2 book - Part 39 of 181
The Ring programming language version 1.5.2 book - Part 39 of 181The Ring programming language version 1.5.2 book - Part 39 of 181
The Ring programming language version 1.5.2 book - Part 39 of 181Mahmoud Samir Fayed
 
Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsRebecca Murphey
 

What's hot (18)

PostgreSQL Open SV 2018
PostgreSQL Open SV 2018PostgreSQL Open SV 2018
PostgreSQL Open SV 2018
 
JQuery
JQueryJQuery
JQuery
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
jQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20PresentationjQuery%20on%20Rails%20Presentation
jQuery%20on%20Rails%20Presentation
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browser
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
 
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
 
Url programming
Url programmingUrl programming
Url programming
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web TestingBDD, ATDD, Page Objects: The Road to Sustainable Web Testing
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
 
The Ring programming language version 1.5.2 book - Part 39 of 181
The Ring programming language version 1.5.2 book - Part 39 of 181The Ring programming language version 1.5.2 book - Part 39 of 181
The Ring programming language version 1.5.2 book - Part 39 of 181
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS Apps
 
Php sql-android
Php sql-androidPhp sql-android
Php sql-android
 

Similar to JSON and Swift, Still A Better Love Story Than Twilight

Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02PL dream
 
Typescript - why it's awesome
Typescript - why it's awesomeTypescript - why it's awesome
Typescript - why it's awesomePiotr Miazga
 
Data analysis and visualization with mongo db [mongodb world 2016]
Data analysis and visualization with mongo db [mongodb world 2016]Data analysis and visualization with mongo db [mongodb world 2016]
Data analysis and visualization with mongo db [mongodb world 2016]Alexander Hendorf
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using RoomNelson Glauber Leal
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
Realm.io par Clement Sauvage
Realm.io par Clement SauvageRealm.io par Clement Sauvage
Realm.io par Clement SauvageCocoaHeads France
 
Browsers with Wings
Browsers with WingsBrowsers with Wings
Browsers with WingsRemy Sharp
 
Data mangling with mongo db the right way [pyconit 2016]
Data mangling with mongo db the right way [pyconit 2016]Data mangling with mongo db the right way [pyconit 2016]
Data mangling with mongo db the right way [pyconit 2016]Alexander Hendorf
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineAndy McKay
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Tomasz Dziuda
 
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"South Tyrol Free Software Conference
 
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...Trivadis
 
Eve - REST API for Humans™
Eve - REST API for Humans™Eve - REST API for Humans™
Eve - REST API for Humans™Nicola Iarocci
 
Working with the Web: 
Decoding JSON
Working with the Web: 
Decoding JSONWorking with the Web: 
Decoding JSON
Working with the Web: 
Decoding JSONSV.CO
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs偉格 高
 
Swipe 2011 - iOS Gems
Swipe 2011 - iOS GemsSwipe 2011 - iOS Gems
Swipe 2011 - iOS GemsKevin O'Neill
 
Das Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesDas Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesStephan Schmidt
 

Similar to JSON and Swift, Still A Better Love Story Than Twilight (20)

Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
 
Typescript - why it's awesome
Typescript - why it's awesomeTypescript - why it's awesome
Typescript - why it's awesome
 
Data analysis and visualization with mongo db [mongodb world 2016]
Data analysis and visualization with mongo db [mongodb world 2016]Data analysis and visualization with mongo db [mongodb world 2016]
Data analysis and visualization with mongo db [mongodb world 2016]
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Realm.io par Clement Sauvage
Realm.io par Clement SauvageRealm.io par Clement Sauvage
Realm.io par Clement Sauvage
 
CSV JSON and XML files in Python.pptx
CSV JSON and XML files in Python.pptxCSV JSON and XML files in Python.pptx
CSV JSON and XML files in Python.pptx
 
Browsers with Wings
Browsers with WingsBrowsers with Wings
Browsers with Wings
 
Data mangling with mongo db the right way [pyconit 2016]
Data mangling with mongo db the right way [pyconit 2016]Data mangling with mongo db the right way [pyconit 2016]
Data mangling with mongo db the right way [pyconit 2016]
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
 
Introduction to ECMAScript 2015
Introduction to ECMAScript 2015Introduction to ECMAScript 2015
Introduction to ECMAScript 2015
 
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
 
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...
Trivadis TechEvent 2016 Polybase challenges Hive relational access to non-rel...
 
Eve - REST API for Humans™
Eve - REST API for Humans™Eve - REST API for Humans™
Eve - REST API for Humans™
 
Working with the Web: 
Decoding JSON
Working with the Web: 
Decoding JSONWorking with the Web: 
Decoding JSON
Working with the Web: 
Decoding JSON
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
Swipe 2011 - iOS Gems
Swipe 2011 - iOS GemsSwipe 2011 - iOS Gems
Swipe 2011 - iOS Gems
 
Das Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based ServicesDas Web Wird Mobil - Geolocation und Location Based Services
Das Web Wird Mobil - Geolocation und Location Based Services
 
Parse.com
Parse.comParse.com
Parse.com
 

More from Donny Wals

Your 🧠 on Swift Concurrency
Your 🧠 on Swift ConcurrencyYour 🧠 on Swift Concurrency
Your 🧠 on Swift ConcurrencyDonny Wals
 
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...Donny Wals
 
The combine triad
The combine triadThe combine triad
The combine triadDonny Wals
 
Building reusable components with generics and protocols
Building reusable components with generics and protocolsBuilding reusable components with generics and protocols
Building reusable components with generics and protocolsDonny Wals
 
Adopting tdd in the workplace
Adopting tdd in the workplaceAdopting tdd in the workplace
Adopting tdd in the workplaceDonny Wals
 
Me and my importers
Me and my importersMe and my importers
Me and my importersDonny Wals
 
Adopting tdd in the workplace
Adopting tdd in the workplaceAdopting tdd in the workplace
Adopting tdd in the workplaceDonny Wals
 
In Defense Of Core Data
In Defense Of Core DataIn Defense Of Core Data
In Defense Of Core DataDonny Wals
 
Effectively Producing And Shipping Frameworks For Multiple Platforms
Effectively Producing And Shipping Frameworks For Multiple PlatformsEffectively Producing And Shipping Frameworks For Multiple Platforms
Effectively Producing And Shipping Frameworks For Multiple PlatformsDonny Wals
 
Talk - git task managers and ci
Talk - git task managers and ciTalk - git task managers and ci
Talk - git task managers and ciDonny Wals
 
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...Donny Wals
 
Marketing strategie Arto
Marketing strategie ArtoMarketing strategie Arto
Marketing strategie ArtoDonny Wals
 
Hoorcollege Flash 9-2-2012
Hoorcollege Flash 9-2-2012Hoorcollege Flash 9-2-2012
Hoorcollege Flash 9-2-2012Donny Wals
 

More from Donny Wals (13)

Your 🧠 on Swift Concurrency
Your 🧠 on Swift ConcurrencyYour 🧠 on Swift Concurrency
Your 🧠 on Swift Concurrency
 
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
 
The combine triad
The combine triadThe combine triad
The combine triad
 
Building reusable components with generics and protocols
Building reusable components with generics and protocolsBuilding reusable components with generics and protocols
Building reusable components with generics and protocols
 
Adopting tdd in the workplace
Adopting tdd in the workplaceAdopting tdd in the workplace
Adopting tdd in the workplace
 
Me and my importers
Me and my importersMe and my importers
Me and my importers
 
Adopting tdd in the workplace
Adopting tdd in the workplaceAdopting tdd in the workplace
Adopting tdd in the workplace
 
In Defense Of Core Data
In Defense Of Core DataIn Defense Of Core Data
In Defense Of Core Data
 
Effectively Producing And Shipping Frameworks For Multiple Platforms
Effectively Producing And Shipping Frameworks For Multiple PlatformsEffectively Producing And Shipping Frameworks For Multiple Platforms
Effectively Producing And Shipping Frameworks For Multiple Platforms
 
Talk - git task managers and ci
Talk - git task managers and ciTalk - git task managers and ci
Talk - git task managers and ci
 
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
 
Marketing strategie Arto
Marketing strategie ArtoMarketing strategie Arto
Marketing strategie Arto
 
Hoorcollege Flash 9-2-2012
Hoorcollege Flash 9-2-2012Hoorcollege Flash 9-2-2012
Hoorcollege Flash 9-2-2012
 

Recently uploaded

Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfGlobus
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfAMB-Review
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?XfilesPro
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownloadvrstrong314
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEJelle | Nordend
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Shahin Sheidaei
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyanic lab
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandIES VE
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Anthony Dahanne
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus
 
Agnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in KrakówAgnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in Krakówbim.edu.pl
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Globus
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAlluxio, Inc.
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...informapgpstrackings
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTier1 app
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 

Recently uploaded (20)

Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 
Agnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in KrakówAgnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in Kraków
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning Framework
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 

JSON and Swift, Still A Better Love Story Than Twilight

  • 1.
  • 2. Hi, I’m Donny. I build iOS apps.
  • 3. Hi, I’m Donny. I build iOS apps.
  • 5. JSON and Swift… Still A Better Love Story Than Twilight
  • 6. Topics • Pre-Swift 4.0 JSON handling • Some things I learned about JSON pre-Swift 4.0 • Handling JSON in Swift 4.0 • Concluding remarks
  • 7. Pre-Swift 4.0 JSON Handling { "items": [{ "line_up": [{ "artist": { "name": "Foo" } }] }] } JSON File:
  • 8. Pre-Swift 4.0 JSON Handling { "items": [{ "line_up": [{ "artist": { "name": "Foo" } }] }] } JSON File: Swift 1.0: if let items = json["items"] as? [[String: AnyObject]] { if let firstItem = items.first { if let item = firstItem as? [String: AnyObject] { if let lineUp = item["line_up"] as? [[String: AnyObject]] { if let firstLineupItem = lineUp.first { if let artist = firstLineupItem["artist"] as? [String: AnyObject] { if let name = artist["name"] as? String { print(name) } } } } } } }
  • 9. Pre-Swift 4.0 JSON Handling { "items": [{ "line_up": [{ "artist": { "name": "Foo" } }] }] } JSON File: Swift 2.0: guard let items = json["items"] as? [String: Any], let firstItem = items.first, let item = firstItem as? [String: Any], let lineUp = firstItem["line_up"] as? [[String: Any]], let firstLineUpItem = lineUp.first, let artist = firstLineUpItem["artist"] as? [String: Any], let name = artist["name"] as? String else { return } print(name)
  • 10. Pre-Swift 4.0 JSON Handling { "items": [{ "line_up": [{ "artist": { "name": "Foo" } }] }] } JSON File: SwiftyJSON guard let item = json["items"].arrayValue.first, let lineUpItem = item["line_up"].arrayValue.first, let name = lineUpItem["artist"]["name"].string else { return } print(name)
  • 11. SwiftyJSON is amazing! guard let item = json["items"].arrayValue.first, let lineUpItem = item["line_up"].arrayValue.first, let name = lineUpItem["artist"]["name"].string else { return } print(name) 😍
  • 12. SwiftyJSON is amazing! guard let item = json["items"].arrayValue.first, let lineUpItem = item["line_up"].arrayValue.first, let name = lineUpItem["artist"]["name"].string else { return } print(name) 😍
  • 14. A performance test { id: 260, name: 'DAS Foute Oktoberfest 20171', start: '2017-02-20T16:00:00+0000', end: '2017-10-07T23:59:00+0000', publish_from: '2016-11-09T08:00:00+0000', publish_to: '2017-10-07T23:59:00+0000', categories: [ { id: 2, name: 'NAME GOES HERE' } ], location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4! 1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532', email: 'random@email.com', id: 169, radius: 500 }, line_up: [ { id: 1, name: 'nino' }, { id: 2, name: 'lisa' }, { id: 7, name: 'kees' }, { id: 4, name: 'Rodney' }, { id: 8, name: 'Oscar' }, { id: 9, name: 'Dick' } ], description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen. rnrnBinnenkort meer info!', image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' }
  • 15. A performance test { id: 260, name: 'DAS Foute Oktoberfest 20171', start: '2017-02-20T16:00:00+0000', end: '2017-10-07T23:59:00+0000', publish_from: '2016-11-09T08:00:00+0000', publish_to: '2017-10-07T23:59:00+0000', categories: [ { id: 2, name: 'NAME GOES HERE' } ], location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4! 1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532', email: 'random@email.com', id: 169, radius: 500 }, line_up: [ { id: 1, name: 'nino' }, { id: 2, name: 'lisa' }, { id: 7, name: 'kees' }, { id: 4, name: 'Rodney' }, { id: 8, name: 'Oscar' }, { id: 9, name: 'Dick' } ], description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen. rnrnBinnenkort meer info!', image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' } • 2080 events
  • 16. A performance test { id: 260, name: 'DAS Foute Oktoberfest 20171', start: '2017-02-20T16:00:00+0000', end: '2017-10-07T23:59:00+0000', publish_from: '2016-11-09T08:00:00+0000', publish_to: '2017-10-07T23:59:00+0000', categories: [ { id: 2, name: 'NAME GOES HERE' } ], location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4! 1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532', email: 'random@email.com', id: 169, radius: 500 }, line_up: [ { id: 1, name: 'nino' }, { id: 2, name: 'lisa' }, { id: 7, name: 'kees' }, { id: 4, name: 'Rodney' }, { id: 8, name: 'Oscar' }, { id: 9, name: 'Dick' } ], description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen. rnrnBinnenkort meer info!', image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' } • 2080 events • Nested objects
  • 17. A performance test { id: 260, name: 'DAS Foute Oktoberfest 20171', start: '2017-02-20T16:00:00+0000', end: '2017-10-07T23:59:00+0000', publish_from: '2016-11-09T08:00:00+0000', publish_to: '2017-10-07T23:59:00+0000', categories: [ { id: 2, name: 'NAME GOES HERE' } ], location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: 'https://www.google.nl/maps/place/Goffertpark/@52.2576689,5.2644167,8.25z/data=!4m5!3m4! 1s0x47c7089b2ce7dff1:0xfd37f35c5b91b9c8!8m2!3d51.8255586!4d5.8366532', email: 'random@email.com', id: 169, radius: 500 }, line_up: [ { id: 1, name: 'nino' }, { id: 2, name: 'lisa' }, { id: 7, name: 'kees' }, { id: 4, name: 'Rodney' }, { id: 8, name: 'Oscar' }, { id: 9, name: 'Dick' } ], description: 'Matrixx presenteert Het Foute Oktoberfest 2017!rnrnZaterdag 7 oktober in een grote feesttent op de Goffertweide in Nijmegen. rnrnBinnenkort meer info!', image_url: 'http://app.appimin.com/filelib/storage/events/58246fa620305_het-foute-oktoberfest-2017.jpg' } • 2080 events • Nested objects • Tested on iPhone 5c
  • 19. A performance test func loadSwifty() { guard let data = getFileData() else { return } let jsonFile = JSON(data: data) for eventJSON in jsonFile["events"].arrayValue { let location = Location(id: eventJSON["location"]["id"].intValue, name: eventJSON["location"]["name"].stringValue, lat: eventJSON["location"]["latitude"].double, lon: eventJSON[“location"]["longitude"].double, address: eventJSON["location"]["address"].stringValue, zipcode: eventJSON[“location"]["zipcode"].stringValue) // etc. } showCompletion() }
  • 20. A performance test func loadSwifty() { guard let data = getFileData() else { return } let jsonFile = JSON(data: data) for eventJSON in jsonFile["events"].arrayValue { let location = Location(id: eventJSON["location"]["id"].intValue, name: eventJSON["location"]["name"].stringValue, lat: eventJSON["location"]["latitude"].double, lon: eventJSON[“location"]["longitude"].double, address: eventJSON["location"]["address"].stringValue, zipcode: eventJSON[“location"]["zipcode"].stringValue) // etc. } showCompletion() } 6.76 seconds to complete
  • 21. A performance test func loadSwifty() { guard let data = getFileData() else { return } let jsonFile = JSON(data: data) for eventJSON in jsonFile["events"].arrayValue { let location = Location(id: eventJSON["location"]["id"].intValue, name: eventJSON["location"]["name"].stringValue, lat: eventJSON["location"]["latitude"].double, lon: eventJSON[“location"]["longitude"].double, address: eventJSON["location"]["address"].stringValue, zipcode: eventJSON[“location"]["zipcode"].stringValue) // etc. } showCompletion() } 6.76 seconds to complete "😭
  • 23. A performance test func loadNormal() { guard let data = getFileData(), let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []), let json = jsonObject as? DWJSON, let events = json["events"] as? [DWJSON] else { return } for eventJSON in events { guard let locationJSON = eventJSON["location"] as? DWJSON, let categoriesJSON = eventJSON["categories"] as? [DWJSON], let lineUpJSON = eventJSON["line_up"] as? [DWJSON] else { return } // etc. } showCompletion() }
  • 24. A performance test func loadNormal() { guard let data = getFileData(), let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []), let json = jsonObject as? DWJSON, let events = json["events"] as? [DWJSON] else { return } for eventJSON in events { guard let locationJSON = eventJSON["location"] as? DWJSON, let categoriesJSON = eventJSON["categories"] as? [DWJSON], let lineUpJSON = eventJSON["line_up"] as? [DWJSON] else { return } // etc. } showCompletion() } 1.84 seconds to complete
  • 25. A performance test func loadNormal() { guard let data = getFileData(), let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []), let json = jsonObject as? DWJSON, let events = json["events"] as? [DWJSON] else { return } for eventJSON in events { guard let locationJSON = eventJSON["location"] as? DWJSON, let categoriesJSON = eventJSON["categories"] as? [DWJSON], let lineUpJSON = eventJSON["line_up"] as? [DWJSON] else { return } // etc. } showCompletion() } 1.84 seconds to complete $😍
  • 26. What did I learn?
  • 27. What did I learn? • Be careful about libraries that make things easy; they might be (very) slow.
  • 28. What did I learn? • Be careful about libraries that make things easy; they might be (very) slow. • Sometimes uglier code is faster (unfortunately).
  • 29. What did I learn? • Be careful about libraries that make things easy; they might be (very) slow. • Sometimes uglier code is faster (unfortunately). • Working with JSON isn’t as bad as it seems in Swift 2.0+.
  • 30. What about Swift 4.0? ❓&❓
  • 32. Introducing Codable struct Category { let id: Int let name: String } let category = Category(id: categoryJSON["id"] as? Int ?? 0, name: categoryJSON["name"] as? String ?? "") < Swift 4.0
  • 33. Introducing Codable struct Category { let id: Int let name: String } let category = Category(id: categoryJSON["id"] as? Int ?? 0, name: categoryJSON["name"] as? String ?? "") < Swift 4.0 struct Category: Codable { let id: Int let name: String } Swift 4.0 let decoder = JSONDecoder() let category = try? decoder.decode(Category.self, from: data)
  • 34. Introducing Codable struct Category { let id: Int let name: String } let category = Category(id: categoryJSON["id"] as? Int ?? 0, name: categoryJSON["name"] as? String ?? "") < Swift 4.0 struct Category: Codable { let id: Int let name: String } Swift 4.0 let decoder = JSONDecoder() let category = try? decoder.decode(Category.self, from: data) Property names are directly mapped to JSON keys
  • 35. Introducing Codable But what if the keys don’t match?
  • 36. Introducing Codable location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: ‘https://www.google.nl/', email: 'random@email.com', id: 169, radius: 500 } But what if the keys don’t match?
  • 37. Introducing Codable location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: ‘https://www.google.nl/', email: 'random@email.com', id: 169, radius: 500 } But what if the keys don’t match?
  • 38. Introducing Codable location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: ‘https://www.google.nl/', email: 'random@email.com', id: 169, radius: 500 } struct Location { let id: Int let name: String let lat: Double? let lon: Double? let address: String let zipcode: String } But what if the keys don’t match?
  • 39. Introducing Codable location: { name: 'Goffertpark, Nijmegen (NL)', address: '', zipcode: '1234AB', city: 'Nijmegen', state: 'Noord-whateverland', country: 'NL', latitude: 51.82548, longitude: 5.836629, url: ‘https://www.google.nl/', email: 'random@email.com', id: 169, radius: 500 } struct Location: Codable { enum CodingKeys: String, CodingKey { case id, name, address, zipcode case lat = "latitude" case lon = "longitude" } let id: Int let name: String let lat: Double? let lon: Double? let address: String let zipcode: String } But what if the keys don’t match?
  • 41. Codable Performance func loadCodable() { guard let data = getFileData() else { return } do { let decoder = JSONDecoder() let eventsResponse = try decoder.decode(EventsResponse.self, from: data) showCompletion() } catch { print(error) } }
  • 42. Codable Performance func loadCodable() { guard let data = getFileData() else { return } do { let decoder = JSONDecoder() let eventsResponse = try decoder.decode(EventsResponse.self, from: data) showCompletion() } catch { print(error) } } 1.82 seconds to complete
  • 43. Codable Performance func loadCodable() { guard let data = getFileData() else { return } do { let decoder = JSONDecoder() let eventsResponse = try decoder.decode(EventsResponse.self, from: data) showCompletion() } catch { print(error) } } 1.82 seconds to complete $😍
  • 44. Codable and Date struct DWDate: Codable { let date: Date? } let jsonString = "{"date": "31-08-2017 +0000"}" let json = jsonString.data(using: .utf8)! do { let decoder = JSONDecoder() let formatter = DateFormatter() formatter.dateFormat = "dd-MM-yyyy Z" decoder.dateDecodingStrategy = .formatted(formatter) let response = try decoder.decode(DWDate.self, from: json) } catch { print(error) }
  • 45. Codable and Date struct DWDate: Codable { let date: Date? } let jsonString = "{"date": ""}" //' ' ' let json = jsonString.data(using: .utf8)! do { let decoder = JSONDecoder() let formatter = DateFormatter() formatter.dateFormat = "dd-MM-yyyy Z" decoder.dateDecodingStrategy = .formatted(formatter) let response = try decoder.decode(DWDate.self, from: json) } catch { print(error) }
  • 46. Codable and Date struct DWDate: Codable { let date: Date? } let jsonString = "{"date": ""}" //' ' ' let json = jsonString.data(using: .utf8)! do { let decoder = JSONDecoder() let formatter = DateFormatter() formatter.dateFormat = "dd-MM-yyyy Z" decoder.dateDecodingStrategy = .formatted(formatter) let response = try decoder.decode(DWDate.self, from: json) } catch { print(error) } dataCorrupted(Swift.DecodingError.Context(codingPath: [__lldb_expr_156.DWDate.(CodingKeys in _995AD5D014A8F9E1965F4BEEB81F4E38).date], debugDescription: "Date string does not match format expected by formatter.", underlyingError: nil))
  • 47. Codable and Date struct DWDate: Codable { let date: Date? init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.date = try? container.decode(Date.self, forKey: .date) } }
  • 48. What else should you know? struct Prize: Codable { enum PrizeType: Int, Codable { case ticket = 1, voucher = 2 } let name: String let type: PrizeType } { "name" : "Test", "type" : 1 }
  • 49. What else should you know? let prize = Prize(name: "Test", type: .ticket) let encoder = JSONEncoder() let result = try! encoder.encode(prize) { "name" : "Test", "type" : 1 }
  • 50. What else should you know? struct EventsResponse: Codable { let events: [Event] } let eventsResponse = try decoder.decode([String: [Event]].self, from: data) let eventsResponse = try decoder.decode(EventsResponse.self, from: data)
  • 52. Concluding remarks • Handling JSON with libraries can be convenient yet slow
  • 53. Concluding remarks • Handling JSON with libraries can be convenient yet slow • The Codable protocol performs really well
  • 54. Concluding remarks • Handling JSON with libraries can be convenient yet slow • The Codable protocol performs really well • Optional date handling is a bit too strict IMO
  • 55. Concluding remarks • Handling JSON with libraries can be convenient yet slow • The Codable protocol performs really well • Optional date handling is a bit too strict IMO • You can do really powerful things with Codable
  • 56. Concluding remarks • Handling JSON with libraries can be convenient yet slow • The Codable protocol performs really well • Optional date handling is a bit too strict IMO • You can do really powerful things with Codable http://benscheirman.com/2017/06/ultimate-guide-to-json-parsing-with-swift-4/