Share
Embed
Transcript
31 slides
-
Decodable - Pairs Taiwan @muukii - eureka, Inc Twitter :
#eureka_meetup -
About Me ‣ muukii <Hiroshi Kimura> ‣ iOS Senior Engineer
at eureka, Inc. ‣ Pairs Taiwan iOS ‣ GitHub : @muukii ‣ https://about.me/muukii ☕ ⌚ -
Agenda ‣ WWDC17 ‣ Swift4 - Codable - Decodable -
Customize & DecodingError ‣ Pairs Taiwan iOS Development ‣ muukii/StackScrollView -
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) -
‣ Too many JSON libraries ‣ SwiftyJSON/SwiftyJSON ‣ muukii/JAYSON ‣
and more. and more. Can We Replace JSON Libraries? -
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) } } -
do { let users = try decoder.decode([User].self, from: data) }
catch let error as DecodingError { } catch { } Error Handling JSONDecoder throw DecodingError -
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): } -
.keyNotFound struct User: Decodable { let age: Int let name:
String } { "name" : "muukii" } -
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 -
{ "age" : 18, "state" : { "isFavorite" : false
} } struct User: Decodable { struct State: Decodable { let isFavorite: String } let state: State } .typeMismatch -
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 -
.valueNotFound { "age" : null, "name" : "muukii" } struct
User: Decodable { let age: Int let name: String } User.age is required -
.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 -
case .dataCorrupted(let context): print(context.debugDescription) // Invalid URL string. print(context.codingPath.map {
$0?.stringValue }) // [nil] Root -> age .dataCorrupted -
Summary ‣ Decodable is useful ‣ Simple code for simple
mappings ‣ Possible custom mapping ‣ DecodingError indicates useful information ‣ KeyPath on caused error ‣ "notFoundKey", "valueNotFound", "keyMismatch" , "dataCorrupted" -
Used techniques • No Interface Builder • TextureGroup/Texture (AsyncDisplayKit) •
muukii/StackScrollView • Module (Request, Service, Component, App) • MVVM with RxSwift • Carthage & CocoaPods • and more… -
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 -
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]) -
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 -
Features class StackScrollView { func append(view: UIView) func remove(view: UIView,
animated: Bool) func scroll(to view: UIView, animated: Bool) } -
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 {} -
Summary ‣ Helpful APIs for Form UI ‣ No longer
need to consider reusing Cells ‣ Nothing is impossible ‣ We can create custom UI for Our Products.