SlideShare uma empresa Scribd logo
1 de 57
Baixar para ler offline
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!

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Semelhante a 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
 

Semelhante a 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
 

Mais de 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
 

Mais de 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
 

Último

Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 

Último (20)

Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 

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/