Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

    View full-size slide

  2. Daiki Matsudate
    @d_date

    View full-size slide

  3. Tokyo
    2018/3/1 - 3

    View full-size slide

  4. typealias Codable = Encodable & Decodable

    View full-size slide

  5. typealias Codable = Encodable & Decodable

    View full-size slide

  6. 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)
    }

    View full-size slide

  7. Usecases of Encodable

    View full-size slide

  8. Case 1. Offline Cacheing

    View full-size slide

  9. Server
    Cache
    Application
    Online
    Offline

    View full-size slide

  10. 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
    }
    }

    View full-size slide

  11. 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

    View full-size slide

  12. 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()
    })
    }

    View full-size slide

  13. 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

    View full-size slide

  14. Case 2. Save token into Keychain

    View full-size slide

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

    View full-size slide

  16. 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

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

  20. Enjoy! Codable

    View full-size slide