【问题标题】:Generic settings class in Swift 2Swift 2 中的通用设置类
【发布时间】:2015-09-15 22:21:25
【问题描述】:

我正在尝试在 Swift 2 中为使用 NSUserDefaults 的任何类型的单一设置实现一个类。

问题:如何定义一个类来存储和检索任何类型的对象,包括Dictionary

我有一个适用于 AnyObject 的解决方案,它由一个通用协议 (Settable) 和一个通用类 (Setting) 组成。 SettingsStoreNSUserDefaults 的包装。

// MARK: Settable Protocol

public protocol Settable {
    typealias T
    init(key: String, defaultValue: T, settingsStore: SettingsStore)
    var value: T { get set }
    func loadCurrentValue()
}

// MARK: Settings Class

public class Setting<T: AnyObject>: Settable {
    private let key: String
    private let defaultValue: T
    private let settingsStore: SettingsStore

    private var currentValue: T?

    public required init(key: String, defaultValue: T, settingsStore: SettingsStore) {
        self.key           = key
        self.defaultValue  = defaultValue
        self.settingsStore = settingsStore
    }

    public var value: T {
        get {
            if self.currentValue == nil {
                self.loadCurrentValue()
            }
            return self.currentValue!
        }
        set {
            self.currentValue = newValue
            self.settingsStore.setObject(newValue.toAnyObject(), forKey: self.key)
        }
    }

    public func loadCurrentValue() {
        let optionalValue: T? = self.settingsStore.objectForKey(key) as? T
        if let value = optionalValue {
            self.currentValue = value
        } else {
            self.currentValue = self.defaultValue
        }
    }
}

这允许我创建这样的设置:

let specialId: Setting<String>
init() {
    self.specialId = Setting<String>(
        key: "specialId",
        defaultValue: "<somevalue>",
        settingsStore: self.settingsStore)
}

问题在于它不适用于值类型,例如 StringBoolIntDoubleArrayDictionary,因为它们都是值类型和值类型不符合AnyObject 协议。

我已经使用基于NSStringNSNumber 的协议和扩展解决了其中一些问题,但是Dictionary 的解决方案被证明是难以捉摸的(我不需要@987654341 的解决方案@ 目前,所以我没有花时间尝试解决那个问题)。

// Change definition of Setting class like this:
public class Setting<T: AnyObjectRepresentable>: Settable {
    ...
}

public protocol AnyObjectRepresentable {
    func toAnyObject() -> AnyObject
    static func fromAnyObject(value: AnyObject) -> Self?
}

extension AnyObjectRepresentable where Self: AnyObject {
    public func toAnyObject() -> AnyObject {
        return self
    }
    public static func fromAnyObject(value: AnyObject) -> AnyObject? {
        return value
    }
}
extension String: AnyObjectRepresentable {
    public func toAnyObject() -> AnyObject {
        return NSString(string: self)
    }
    public static func fromAnyObject(value: AnyObject) -> String? {
        let convertedValue = value as? String
        return convertedValue
    }
}
extension Bool: AnyObjectRepresentable {
    public func toAnyObject() -> AnyObject {
        return NSNumber(bool: self)
    }
    public static func fromAnyObject(value: AnyObject) -> Bool? {
        let convertedValue = value as? Bool
        return convertedValue
    }
}
// Add extensions for Int and Double that look like the above extension for Bool.

我为Dictionary 尝试了两种不同的方法。第一个类似于String的方法:

extension Dictionary: AnyObjectRepresentable {
    public func toAnyObject() -> AnyObject {
        let value = self as NSDictionary
        return value
    }
    public static func fromAnyObject(value: AnyObject) -> Dictionary? {
        let convertedValue = value as? Dictionary
        return convertedValue
    }
}

Xcode 在toAnyObject() 方法实现的第一行给了我以下错误:

'Dictionary' 不能转换为 'NSDictionary'

接下来我尝试直接扩展NSDictionary

extension NSDictionary: AnyObjectRepresentable {
    public func toAnyObject() -> AnyObject {
        return NSDictionary(dictionary: self)
    }
    public static func fromAnyObject(value: AnyObject) -> NSDictionary? {
        let convertedValue = value as? NSDictionary
        return convertedValue
    }
}

Xcode 在fromAnyObject() 的声明中给出以下错误:

非最终类 'NSDictionary' 中的方法 'fromAnyObject' 必须返回 Self 以符合协议 'AnyObjectRepresentable'

我很机智。这可以解决吗?

谢谢,
大卫

2015-09-15 16:30 更新

作为背景,这里是SettingsStore的定义和实现:

public protocol SettingsStore {
    func objectForKey(key: String) -> AnyObject?
    func setObject(value: AnyObject?, forKey key: String)
    func dictionaryForKey(key: String) -> [String:AnyObject]?
}
public class UserDefaultsSettingsStore {
    private let userDefaults: NSUserDefaults
    public init() {
        self.userDefaults = NSUserDefaults.standardUserDefaults()
    }
    public init(suiteName: String) {
        self.userDefaults = NSUserDefaults(suiteName: suiteName)!
    }
}
extension UserDefaultsSettingsStore: SettingsStore {
    public func objectForKey(key: String) -> AnyObject? {
        return self.userDefaults.objectForKey(key)
    }
    public func setObject(value: AnyObject?, forKey key: String) {
        self.userDefaults.setObject(value, forKey: key)
        self.userDefaults.synchronize()
    }
    public func dictionaryForKey(key: String) -> [String : AnyObject]? {
        return self.userDefaults.dictionaryForKey(key)
    }
}

【问题讨论】:

  • 不使用 AnyObject,使用 Any 怎么样?
  • 关于您的错误,请查看Protocol fun returning Self
  • 我之前看过 - Rob Napier 关于这个主题的文章非常好,但不幸的是它在这种情况下对我没有帮助。

标签: swift dictionary swift2


【解决方案1】:

如果您将 AnyObject 替换为 Any,我想您会得到您想要的结果。具体来说,替换这一行:

public class Setting<T: AnyObject>: Settable {

用这条线

public class Setting<T: Any>: Settable {

【讨论】:

  • 我试过了,但后来我遇到了 SettingsStore 的问题,它用于从/向 NSUserDefaults 读取和写入设置。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
相关资源
最近更新 更多