Slide 1

Slide 1 text

Decodable - Pairs Taiwan @muukii - eureka, Inc Twitter : #eureka_meetup

Slide 2

Slide 2 text

About Me ‣ muukii ‣ iOS Senior Engineer at eureka, Inc. ‣ Pairs Taiwan iOS ‣ GitHub : @muukii ‣ https://about.me/muukii ☕ ⌚

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Agenda ‣ WWDC17 ‣ Swift4 - Codable - Decodable - Customize & DecodingError ‣ Pairs Taiwan iOS Development ‣ muukii/StackScrollView

Slide 5

Slide 5 text

typealias Codable = Decodable & Encodable Swift4

Slide 6

Slide 6 text

Decodable • JSONDecoder [ { "name" : "muukii", "age" : 18, "state" : { "isFavorite" : false }, "flags" : ["a", "b", "c"] }, … … ] struct User: Decodable { struct State: Decodable { let isFavorite: Bool } let name: String let age: Int let state: State let flags: [String] } let decoder = JSONDecoder() let users = try decoder.decode([User].self, from: data)

Slide 7

Slide 7 text

‣ Too many JSON libraries ‣ SwiftyJSON/SwiftyJSON ‣ muukii/JAYSON ‣ and more. and more. Can We Replace JSON Libraries?

Slide 8

Slide 8 text

Custom Decoding struct User: Decodable { private enum CodingKeys: String, CodingKey { case name = "username" case age case flags } let name: String let age: Int let flags: [String] init(from decoder: Decoder) throws { let c = try decoder.container(keyedBy: CodingKeys.self) name = try c.decode(String.self, forKey: .name) age = try c.decode(Int.self, forKey: .age) flags = try c.decode([String].self, forKey: .flags) } }

Slide 9

Slide 9 text

More https://developer.apple.com/documentation/foundation/archives_and_serialization/ using_json_with_custom_types Sample Code
 Using JSON with Custom Types

Slide 10

Slide 10 text

do { let users = try decoder.decode([User].self, from: data) } catch let error as DecodingError { } catch { } Error Handling JSONDecoder throw DecodingError

Slide 11

Slide 11 text

DecodingError let error: DecodingError switch error { case .keyNotFound(let key, let context): case .typeMismatch(let type, let context): case .valueNotFound(let type, let context): case .dataCorrupted(let context): }

Slide 12

Slide 12 text

.keyNotFound struct User: Decodable { let age: Int let name: String } { "name" : "muukii" }

Slide 13

Slide 13 text

case .keyNotFound(let key, let context): print(key) // age print(context.debugDescription) // Key not found when expecting non-optional type A for coding key "age" print(context.codingPath.map { $0?.stringValue }) // [nil, Optional("age")] Root -> age .keyNotFound

Slide 14

Slide 14 text

{ "age" : 18, "state" : { "isFavorite" : false } } struct User: Decodable { struct State: Decodable { let isFavorite: String } let state: State } .typeMismatch

Slide 15

Slide 15 text

case .typeMismatch(let type, let context): print(type) // String print(context.debugDescription) // Expected to decode String but found a number instead. print(context.codingPath.map { $0?.stringValue }) // [nil, Optional("state"), Optional("isFavorite")] .typeMismatch Root -> state -> isFavorite

Slide 16

Slide 16 text

.valueNotFound { "age" : null, "name" : "muukii" } struct User: Decodable { let age: Int let name: String } User.age is required

Slide 17

Slide 17 text

.valueNotFound case .valueNotFound(let type, let context): print(type) // Int print(context.debugDescription) // Found null value when expecting non-optional type UInt for coding key "age" print(context.codingPath.map { $0?.stringValue }) // [nil, Optional("age")] Root -> age

Slide 18

Slide 18 text

.dataCorrupted struct Image: Decodable { let url: URL } { "url" : "" }

Slide 19

Slide 19 text

case .dataCorrupted(let context): print(context.debugDescription) // Invalid URL string. print(context.codingPath.map { $0?.stringValue }) // [nil] Root -> age .dataCorrupted

Slide 20

Slide 20 text

Summary ‣ Decodable is useful ‣ Simple code for simple mappings ‣ Possible custom mapping ‣ DecodingError indicates useful information ‣ KeyPath on caused error ‣ "notFoundKey", "valueNotFound", "keyMismatch" , "dataCorrupted"

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

02 - Global

Slide 23

Slide 23 text

Used techniques • No Interface Builder • TextureGroup/Texture (AsyncDisplayKit) • muukii/StackScrollView • Module (Request, Service, Component, App) • MVVM with RxSwift • Carthage & CocoaPods • and more…

Slide 24

Slide 24 text

StackScrollView

Slide 25

Slide 25 text

What is StackScrollView? • iOS Form UI Builder • Doesn't use UITableViewCell / UICollectionViewCell • UIView based Cell • Initialization is faster than UIStackView • No built-in UI-Components • No longer need to consider reusing Cells • Self-sizing with AutoLayout • Nothing is impossible

Slide 26

Slide 26 text

Usage StackScrollView let view = StackScrollView() let cell_1 = LabelStackCell() view.append(views: [cell_1]) let cell_2 = LabelStackCell() view.append(views: [cell_2]) let cell_3 = LabelStackCell() view.append(views: [cell_3])

Slide 27

Slide 27 text

Usage StackScrollView final class LabelStackCell: UIView { let label = UILabel() init() { super.init(frame: .zero) addSubview(label) label <- Edges(16) // nakiostudio/EasyPeasy } } Label UIView must have sufficient internal constraints

Slide 28

Slide 28 text

Features class StackScrollView { func append(view: UIView) func remove(view: UIView, animated: Bool)
 func scroll(to view: UIView, animated: Bool) }

Slide 29

Slide 29 text

Features protocol StackCellType : class { } extension StackCellType where Self : UIView { var stackScrollView: StackScrollView? { get } func scrollToSelf(animated: Bool) func updateLayout(animated: Bool) func remove() } Recalculate size of view extension LabelStackCell : StackCellType {}

Slide 30

Slide 30 text

Summary ‣ Helpful APIs for Form UI ‣ No longer need to consider reusing Cells ‣ Nothing is impossible ‣ We can create custom UI for Our Products.

Slide 31

Slide 31 text

Thank you