$30 off During Our Annual Pro Sale. View Details »

Advanced Usecase for Codable

d_date
December 20, 2017

Advanced Usecase for Codable

Codable is consist of not only Decodable, but also Encodable

2018/01/20 Swift 愛好会合宿
2018/01/24 potatotips

d_date

December 20, 2017
Tweet

More Decks by d_date

Other Decks in Programming

Transcript

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

  2. Daiki Matsudate @d_date

  3. Tokyo 2018/3/1 - 3

  4. Codable

  5. typealias Codable = Encodable & Decodable

  6. typealias Codable = Encodable & Decodable

  7. None
  8. Encodable

  9. 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) }
  10. Usecases of Encodable

  11. Case 1. Offline Cacheing

  12. Server Cache Application Online Offline

  13. static func save<T: Codable>(response: Response<T>, 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 } }
  14. static func save<T: Codable>(response: Response<T>, 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
  15. func load<T: Codable>(fileName: String) -> Observable<Response<T>> { 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() }) }
  16. func load<T: Codable>(fileName: String) -> Observable<Response<T>> { 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
  17. Case 2. Save token into Keychain

  18. func signUp() -> Single<AuthenticatedUserModel> { return useCase.signUp() .map({ (user) ->

    AuthenticatedUserModel in let data = try JSONEncoder().encode((user)) AccessToken.set(data: data) }) }
  19. func signUp() -> Single<AuthenticatedUserModel> { 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
  20. var currentUser: AuthenticatedUserModel? { do { guard let data =

    AccessToken.getData() else { return nil } return try JSONDecoder().decode(AuthenticatedUserModel.self, from: data) } catch { return nil } }
  21. 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
  22. 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
  23. Enjoy! Codable