Slide 1

Slide 1 text

Advanced Usecase for Codable Daiki Matsudate / @d_date 2018/01/24

Slide 2

Slide 2 text

Daiki Matsudate @d_date

Slide 3

Slide 3 text

Tokyo 2018/3/1 - 3

Slide 4

Slide 4 text

Codable

Slide 5

Slide 5 text

typealias Codable = Encodable & Decodable

Slide 6

Slide 6 text

typealias Codable = Encodable & Decodable

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Encodable

Slide 9

Slide 9 text

let data = """ { "id": 1, "to": “sample", "message": “஀ੜ೔͓ΊͰͱ͏͍͟͝·͢!" } """.data(using: .utf8)! do { //Decode let model = try JSONDecoder().decode(Model.self, from: data) //Encode let encodedData = try JSONEncoder().encode(model) // Data } catch { print(error) }

Slide 10

Slide 10 text

Usecases of Encodable

Slide 11

Slide 11 text

Case 1. Offline Cacheing

Slide 12

Slide 12 text

Server Cache Application Online Offline

Slide 13

Slide 13 text

static func save(response: Response, fileName: String) throws { guard let fileUrl = FileCacheHandler.filePath(fileName: fileName, pagination: response.header) else { throw CacheError.cachesPathNotExist } do { let data = try JSONEncoder().encode(response.body) let directoryUrl = fileUrl.deletingLastPathComponent() if !FileManager.default.fileExists(atPath: directoryUrl.path) { try FileManager.default.createDirectory(at: directoryUrl, withIntermediateDirectories: true, attributes: nil) } try data.write(to: fileUrl) print("saved: \(fileUrl)") } catch { print(error.localizedDescription) throw error } }

Slide 14

Slide 14 text

static func save(response: Response, fileName: String) throws { guard let fileUrl = FileCacheHandler.filePath(fileName: fileName, pagination: response.header) else { throw CacheError.cachesPathNotExist } do { let data = try JSONEncoder().encode(response.body) let directoryUrl = fileUrl.deletingLastPathComponent() if !FileManager.default.fileExists(atPath: directoryUrl.path) { try FileManager.default.createDirectory(at: directoryUrl, withIntermediateDirectories: true, attributes: nil) } try data.write(to: fileUrl) print("saved: \(fileUrl)") } catch { print(error.localizedDescription) throw error } } Encoding Json to data Write data to local path

Slide 15

Slide 15 text

func load(fileName: String) -> Observable> { return Observable.create({ (observer) -> Disposable in guard let fileUrl = FileCacheHandler.filePath(fileName: fileName) else { observer.onError(CacheError.cachesPathNotExist) return Disposables.create() } guard FileManager.default.fileExists(atPath: fileUrl.path) else { observer.onError(CacheError.cacheNotExist) return Disposables.create() } do { let data = try Data(contentsOf: fileUrl) let model = try JSONDecoder().decode(T.self, from: data) print("loaded: \(fileUrl)") let response = Response(statusCode: 200, header: [:], body: model) observer.onNext(response) } catch { observer.onError(error) } return Disposables.create() }) }

Slide 16

Slide 16 text

func load(fileName: String) -> Observable> { return Observable.create({ (observer) -> Disposable in guard let fileUrl = FileCacheHandler.filePath(fileName: fileName) else { observer.onError(CacheError.cachesPathNotExist) return Disposables.create() } guard FileManager.default.fileExists(atPath: fileUrl.path) else { observer.onError(CacheError.cacheNotExist) return Disposables.create() } do { let data = try Data(contentsOf: fileUrl) let model = try JSONDecoder().decode(T.self, from: data) print("loaded: \(fileUrl)") let response = Response(statusCode: 200, header: [:], body: model) observer.onNext(response) } catch { observer.onError(error) } return Disposables.create() }) } Load data from local path Decode data

Slide 17

Slide 17 text

Case 2. Save token into Keychain

Slide 18

Slide 18 text

func signUp() -> Single { return useCase.signUp() .map({ (user) -> AuthenticatedUserModel in let data = try JSONEncoder().encode((user)) AccessToken.set(data: data) }) }

Slide 19

Slide 19 text

func signUp() -> Single { return useCase.signUp() .map({ (user) -> AuthenticatedUserModel in let data = try JSONEncoder().encode((user)) AccessToken.set(data: data) }) } Saving data in Keychain Encoding object into data

Slide 20

Slide 20 text

var currentUser: AuthenticatedUserModel? { do { guard let data = AccessToken.getData() else { return nil } return try JSONDecoder().decode(AuthenticatedUserModel.self, from: data) } catch { return nil } }

Slide 21

Slide 21 text

var currentUser: AuthenticatedUserModel? { do { guard let data = AccessToken.getData() else { return nil } return try JSONDecoder().decode(AuthenticatedUserModel.self, from: data) } catch { return nil } } Get data from keychain Decoding data into Model

Slide 22

Slide 22 text

Recap • In general, Codable is very useful for decoding json into your model • Sometimes Encodable is also useful to store your model as data • We should think about DB is needed for your app

Slide 23

Slide 23 text

Enjoy! Codable