Skip to content
ApolloZhu edited this page Sep 18, 2019 · 4 revisions

最后,我们再来看看如何把你的存储方案也适配 EFStorage。

// 如果是用 Swift Package Manager 集成的话:
import EFStorageCore
// CocoaPods 集成的则还是一样导入:
import EFStorage

接下来我们就可以开始了。

注意:把实例中的 <#ExampleStorage#> 替换为实际你存储方案的名字!

实现 EFUnderlyingStorage

extension <#ExampleStorage#>: EFUnderlyingStorage {
    public class func makeDefault() -> Self {
        // ... 这个方法返回默认容器的实现
    }
}

有的时候,你的存储方案并不一定能够成功构造一个默认容器,这种情况则实现 EFFailableUnderlyingStorage

extension <#ExampleStorage#>: EFFailableUnderlyingStorage {
    public class func makeDefault() -> Self? {
        // ... 返回默认容器或者 nil
    }
}

定义可存储内容的协议

public protocol <#ExampleStorage#>Storable {
    func as<#ExampleStorage#>Storable() -> <#ExampleStorage#>Storable//可以看情况加上 ! 或者 ?
    static func from<#ExampleStorage#>(_ <#exampleStorage#>: <#ExampleStorage#>, forKey key: String) -> Self?
}

然后(通过添加 extension 等方法)让需要被存储的(常见)类型实现 <#ExampleStorage#>Storable 协议。

当然,这个协议完全是由你决定的,所以像自带的几个存储方案返回 Result<StorableType, Error>, 甚至写成和上面的协议完全不一样也是可以的。

实现 EFStorage<#ExampleStorage#>Ref

继承 EFStorage 的优良传统/原始设计,我们通过实现 EFSingleInstanceStorageReference 来“保证”这是个单例

public class EFStorage<#ExampleStorage#>Ref<Content: <#ExampleStorage#>Storable>: EFSingleInstanceStorageReference {
    public required init(
        // 这个看起来很长的参数是说,不要直接调用这个构造器,否则后果自负
        iKnowIShouldNotCallThisDirectlyAndIsResponsibleForUnexpectedBehaviorMyself: Bool,
        forKey key: String, in storage: <#ExampleStorage#>//? // 根据情况加上
    ) {
        self.key = key
        self.storage = storage
        self.content = Content.from<#ExampleStorage#>(storage, forKey: key)
    }
    
    public let key: String
    public let storage: <#ExampleStorage#>//?
    public var content: Content? {
        didSet {
            if let newValue = content {
                storage/*?*/.set(newValue.as<#ExampleStorage#>Storable(), forKey: key)
            } else {
                storage/*?*/.removeObject(forKey: key)
            }
        }
    }
}

实现 @propertyWrapper 属性包装器

你可以不这么做,但我想不明白为什么。

@propertyWrapper
public struct EFStorage<#ExampleStorage#><Content: <#ExampleStorage#>Storable>: EFSingleInstanceStorageReferenceWrapper {
    public var _ref: EFStorage<#ExampleStorage#>Ref<Content>
    public var wrappedValue: Content {
        get {
            if let content = _ref.content { return content }
            let defaultContent = makeDefaultContent()
            if persistDefaultContent { _ref.content = defaultContent }
            return defaultContent
        }
        set { _ref.content = newValue }
    }
    
    public let persistDefaultContent: Bool
    public let makeDefaultContent: () -> Content
    public func removeContentFromUnderlyingStorage() {
        _ref.content = nil
    }
    
    public init(
        __ref: EFStorage<#ExampleStorage#>Ref<Content>,
        makeDefaultContent: @escaping () -> Content,
        persistDefaultContent: Bool
    ) {
        self._ref = __ref
        self.makeDefaultContent = makeDefaultContent
        self.persistDefaultContent = persistDefaultContent
    }
}

允许 @dynamicMemberLookup 动态成员查找

谁不喜欢黑魔法呢?

public extension EFUnderlyingStorageWrapper {
    subscript<T: <#ExampleStorage#>Storable>(
        dynamicMember key: String
    ) -> T? where Base == <#ExampleStorage#> {
        get {
            return EFStorage<#ExampleStorage#>Ref.forKey(key, in: base).content
        }
        set {
            EFStorage<#ExampleStorage#>Ref.forKey(key, in: base).content = newValue
        }
    }
    
    subscript<T: <#ExampleStorage#>Storable>(
        dynamicMember key: String
    ) -> T? where Base == <#ExampleStorage#>.Type {
        get {
            return EFStorage<#ExampleStorage#>Ref.forKey(key).content
        }
        set {
            EFStorage<#ExampleStorage#>Ref.forKey(key).content = newValue
        }
    }
}