68
Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

  • Upload
    others

  • View
    14

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Swift's Encoderand Decoder Protocols

Kaitlin MaharSoftware Engineer @ MongoDB

@k__mahar @kmahar

Page 2: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

What is encoding?

EncoderSwift type External representation

etc...

Scalar (e.g. Int)structclassenum

Page 3: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

What is encoding?

JSONEncoder

Page 4: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

What is decoding?

DecoderSwift type External representation

etc...

Scalar (e.g. Int)structclassenum

Page 5: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

What is decoding?

JSONDecoder

Page 6: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Swift 4 introduced a standardized approach to encoding and decoding.

How does it actually work?

Page 7: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Why does it matter?

● Customize how your types are encoded and decoded

○ Omit or rename properties, flatten nested structs...

● Write your own encoder and/or decoder

○ MongoDB driver

■ BSONEncoder: Swift type → MongoDB document

■ BSONDecoder: MongoDB document → Swift type

Page 8: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

What we'll talk about

● The public API● Internals● Limitations

Page 9: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

The Public API

Page 10: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

An Encodable type knows how to write itself to an Encoder.

Page 11: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

● Automatic conformance if all properties are Encodable

● Types can provide custom implementations

● Format agnostic: write it once, works with any Encoder!

Page 12: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

A Decodable type knows how to initialize by reading from a Decoder.

Page 13: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

● Automatic conformance if all properties are Decodable

● Types can provide custom implementations

● Write it once, works with any Decoder

Page 14: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar
Page 15: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Types With Built-In Codable Support

● Numeric types● Bool● String● If the values they contain are Encodable / Decodable:

○ Array○ Set○ Dictionary○ Optional

● Common Foundation types: URL, Data, Date, etc.

Page 16: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

… and that's it!

Making Types Codable

Page 17: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Using Encoders and Decoders

Page 18: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Using An Encoder

JSONEncoderEncodable value of type T

UTF-8 encoded Data

Page 19: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Using An Encoder

Page 20: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Why doesn't the API match the Encodable protocol?

Page 21: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

_JSONEncoder: Encoder

JSONEncoder

Why doesn't the API match the Encodable protocol?

private

● Not dictated by any protocol ● Allows setting top-level options

(e.g. DateEncodingStrategy)● Simple API, just one method

● Implements Encoder protocol● Actually does the encoding work● More complex API (stay tuned)

Page 22: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Using A Decoder

JSONDecoderDecodable value of type T

Type to decode to, and UTF-8 encoded Data

Page 23: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Using A Decoder

Data we got from encoding

Page 24: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

_JSONDecoder: Decoder

JSONDecoder

Why doesn't the API match the Decodable protocol?

private

Page 25: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Ok, so… what do these protocols actually require?

Page 26: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

Single Value Unkeyed Keyed

one value sequence of values key/value pairs

provides containers: views into storage

Page 27: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

In code...

SingleValueEncodingContainer

UnkeyedEncodingContainer

KeyedEncodingContainer<Key>

Encoder

Page 28: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoding containers support storing three types of values.

nil

Bool, String, Double, Floatall Int and UInt types

Encodable type

base case 1: nil

base case 2: primitives

recursive case

Page 29: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

nil

primitive

Encodable

SingleValueEncodingContainer

Page 30: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

nil

primitive

Encodable

SingleValueEncodingContainer

UnkeyedEncodingContainer

Page 31: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encodable

primitive

nil

KeyedEncodingContainerProtocol

Page 32: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

CodingKey

KeyedEncodingContainer<Key>

Encoder

Page 33: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

CodingKey

Requirements:● Initializable by String

and/or Int● Must have a String

representation● May have an Int

representation

Synthesized conformance for enums!

Page 34: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

Single Value Unkeyed Keyed

Unkeyed Keyed Unkeyed Keyed recursive case

Page 35: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Keyed

Unkeyed

UnkeyedEncodingContainer

KeyedEncodingContainerProtocol

Unkeyed

Keyed

Page 36: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

So how are these containers used?

Page 37: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar
Page 38: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

KeyedEncodingContainer

name color

"Chester" "tan"

Page 39: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

KeyedEncodingContainer

name color

"Chester" "tan"

Page 40: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

KeyedEncodingContainer

name color

"Chester" "tan"

Compiler generated!

Page 41: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

But what if we don't want the defaults?

Encoder

KeyedEncodingContainer

firstName color

"Chester" "tan"We can override just CodingKeys to rename keys but keep the default encode(to:) implementation.

Page 42: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

But what if we don't want the defaults?

We can override just CodingKeys to omit keys altogether.

Encoder

KeyedEncodingContainer

name

"Chester"

Page 43: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

But what if we don't want the defaults?

Encoder

KeyedEncodingContainer

name color

"chester" "orange"Or we can override encode(to:) to further customize behavior.

Page 44: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Let's make things more complicated...

Page 45: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoder

KeyedContainer name cats

"Kaitlin"

Unkeyed

KeyedContainer name color

"Chester" "tan"

KeyedContainer name color

"Roscoe" "orange"

CatOwner

catscats[1]cats[0]

Page 46: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

KeyedContainer name color

"Roscoe" "orange"

Unkeyed

Encoder

name cats

"Kaitlin"

KeyedContainer

KeyedContainer

name color

"Chester" "tan"

Page 47: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

KeyedContainer name color

"Roscoe" "orange"

Unkeyed

KeyedContainer

name color

"Chester" "tan"

Encoder

name cats

"Kaitlin"

KeyedContainer

Page 48: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Alternatively...

Page 49: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

KeyedContainer name color

"Roscoe" "orange"

Unkeyed

name color

"Chester" "tan"

Encoder

name cats

"Kaitlin"

KeyedContainer

KeyedContainer

Again, compiler generated!

Page 50: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Weren't we also talking about decoding?

Page 51: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Encoding: putting values into containers

Decoding: taking values out of containers

Page 52: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Decoder

Single Value Unkeyed Keyed

Unkeyed Keyed Unkeyed Keyed recursive case

Page 53: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

In code...Decoder

SingleValueDecodingContainer

UnkeyedDecodingContainer

KeyedDecodingContainer<Key>

Page 54: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Decoding containers support retrieving three types of values.

nil

Bool, String, Double, Floatall Int and UInt types

Decodable type

base case 1: nil

base case 2: primitives

recursive case

Page 55: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

SingleValueDecodingContainer

nil

primitive

Decodable

Page 56: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

nil

primitive

Decodable

UnkeyedDecodingContainer

Page 57: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

KeyedDecodingContainerProtocol

nil

primitive

Decodable

Page 58: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Decoder

KeyedDecodingContainer

name color

"Chester" "tan"

Page 59: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Decoder

KeyedDecodingContainer

name color

"Chester" "tan"

Page 60: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Decoder

KeyedDecodingContainer

name color

"Chester" "tan"

Compiler generated!

Page 61: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Public API Takeaways

● Types opt in by conforming to Encodable and/or Decodable● Many types get conformance for free, but can customize when

needed ● Public types (e.g. JSONEncoder) do *not* implement the

corresponding protocols!● Encoders and Decoders used container-based APIs for

reading from/writing to storage● The Encoder and Decoder APIs are very similar!

Page 62: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Underneath the Hood

Page 63: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Typical Structure

_MyEncoder: Encoder

storage

private

MyEncoder

_MyDecoder: Decoder

storage

private

MyDecoder

Page 64: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Storage

In what format do I store values while I am still in the middle of encoding/decoding?

● JSON: NS* types that work with JSONSerialization.

● PropertyList: NS* types that work with PropertyListSerialization.

● BSON: types conforming to BsonValue that work with MongoDB documents.

How do I track where I am in the maze of nested containers?

● JSON, BSON, PropertyList: stack with whatever is backing the current container on top

Page 65: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

4 more small but important things to note:

1. SingleValueXContainer is often just implemented via an extension of the private Encoder type.

2. The Encoder must enforce that only one value is written to a SingleValueEncodingContainer.

3. There are various bookkeeping requirements on the protocols for tracking the path of keys taken so far.

4. There are also superEncoder and superDecoder requirements for use with classes.

Page 66: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Limitations

● Lots of boilerplate required for all of the containers, and the different encode and decode methods that they support

● Depending on design, you may end up duplicating a lot of code from JSONEncoder etc.

● Types cannot be extended to become Decodable (but should it be possible?)

Page 67: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

In conclusion...

● The API makes Codable conformance trivial in many cases, but also allows

for very advanced customization when needed.

● The API makes it possible to write Encoders and Decoders that don't know

what the types using them look like, and makes it possible for types to write

encode methods without caring about the actual output format!

● Investigating the standard library source code and writing your own

encoder/decoder reveals some hidden requirements.

Page 68: Swift's Encoder and Decoder Protocols - Kaitlin Mahar · Swift's Encoder and Decoder Protocols Kaitlin Mahar Software Engineer @ MongoDB @k__mahar @kmahar

Thank you!

Kaitlin MaharSoftware Engineer @ MongoDB

@k__mahar @kmahar