Swift: a protocol abstraction persistence

Foreword

Before this paper we define a Parsablefor deserialization

protocol Parsable {
  static func parse(data: Data) -> Result<Self>
}
复制代码

If we give the type of custom add a persistent feature, the same can also define a protocol that type comply with this agreement have 持久化this feature.

Cachable

public protocol Cachable {
  /// 存入沙盒
  ///
  /// - Parameter path: 路径
  /// - Returns: 结果
  @discardableResult
  func save(at path: String) -> Result<Void, Error>

  /// 从沙盒中取
  ///
  /// - Parameter path: 路径
  /// - Returns: 结果
  static func get(fromCache path: String) -> Self?
}
复制代码

CachableIt defines two methods deposit and take, then we have to Cachableadd the default implementation.

Codable

Most of the serialization and de-serialization will use very convenient inCodable

extension Cachable where Self: Codable {
  @discardableResult
  public func save(at path: String) -> Result<Void, Error> {
    let url = URL(fileURLWithPath: path)
    do {
      let data = try JSONEncoder().encode(self)
      try data.write(to: url)
      return .success(())
    } catch {
      print("Cachable: 存储沙盒失败 - \(error.localizedDescription)")
      return .failure(error)
    }
  }

  public static func get(fromCache path: String) -> Self? {
    let url = URL(fileURLWithPath: path)
    do {
      let data = try Data(contentsOf: url)
      return try JSONDecoder().decode(self, from: data)
    } catch {
      print("Cachable: 从沙盒中获取失败 - \(error.localizedDescription)")
      return nil
    }
  }
}
复制代码

As a result, the type of follow up Codableand also want to follow Cachableyou free access to the above two methods.

struct Car: Codable {
  var engine: String
  var name: String
  var type: String
}

extenstion Car: Cachale {}

// 获取沙盒中缓存的car
let carCachePath = getMyCarCachePath()
let myCacheCar = Car.get(fromCache: carCachePath)

// 缓存bmw
let bmw = Car(engine: "V8", name: "X7", type: "xDrive50i")
bmw.save(at: carCachePath)
复制代码

Note: We use @discardableResultmarked save(at:)method, the purpose is to let the compiler does not warn us not to use save(at:)the return value. Many ways chained calls to have this mark, for example Alamofireon the use of the mark.

String、Data

We can also give Stringand Dataalso add this functionality.

extension Cachable where Self == String {
  @discardableResult
  public func save(at path: String) -> Result<Void, Error> {
    let url = URL(fileURLWithPath: path)
    do {
      if let data = self.data(using: .utf8) {
        try data.write(to: url)
        return .success(())
      } else {
        return .failure(WWError.stringToDataError)
      }
    } catch {
      print("Cachable: 存储沙盒失败 - \(error.localizedDescription)")
      return .failure(error)
    }
  }

  public static func get(fromCache path: String) -> Self? {
    let url = URL(fileURLWithPath: path)
    do {
      let data = try Data(contentsOf: url)
      return self.init(data: data, encoding: .utf8)
    } catch {
      print("Cachable: 从沙盒中获取失败 - \(error.localizedDescription)")
      return nil
    }
  }
}
复制代码

DataThe same is true, we may have to go to achieve.

SwiftProtobuf

If you have to use SwiftProtobufit can also give SwiftProtobufthe Messageadd this functionality.

extension Cachable where Self: SwiftProtobuf.Message {
  @discardableResult
  func save(at path: String) -> Result<Void, Error> {
    let url = URL(fileURLWithPath: path)
    do {
      let data = try serializedData()
      try data.write(to: url)
      return .success(())
    } catch {
      print("Cachable: 存储沙盒失败 - \(error.localizedDescription)")
      return .failure(error)
    }
  }

  static func get(fromCache path: String) -> Self? {
    let url = URL(fileURLWithPath: path)
    do {
      let data = try Data(contentsOf: url)
      return try self.init(serializedData: data)
    } catch {
      print("Cachable: 从沙盒中获取失败 - \(error.localizedDescription)")
      return nil
    }
  }
}
复制代码

After adding the default implementation, we Cachablealready have a field day, as long as meet Codableor SwiftProtobufinside Messageand followed Cachableon a free persisted.

to sum up

protocolAbsolutely it is used to describe certain features of the weapon , but not the type of restrictions, everything Jieke follow. JSON want to turn model to follow Decodable, you want to persist an object to follow our Cachable...

As long as you want to provide some kind of function, the use of protocolabstraction, it is added to the default implementation, who wants to use this feature follow it, do not want and will not redundant.

Reproduced in: https: //juejin.im/post/5cfb67cb6fb9a07ee958622b

Guess you like

Origin blog.csdn.net/weixin_34380781/article/details/91466464