有没有办法在Swift中通过属性共享getter和setter?

时间:2016-01-27 16:47:16

标签: ios swift

我正在构建帮助程序以启用对NSUserDefaults属性的类型化访问。像这样:

struct UserDefaults {

  private static var standardUserDefaults: NSUserDefaults = {
    return NSUserDefaults.standardUserDefaults()
  }()

  private static let propKey = "PROP"
  static var prop: Bool {
    get {
      return standardUserDefaults.boolForKey(propKey)
    }
    set {
      standardUserDefaults.setBool(newValue, forKey: propKey)
      standardUserDefaults.synchronize()
    }
  }

}

这样我可以有一个很好的语法来读写NSUserDefaults

UserDefaults.prop // read
UserDefaults.prop = false // write

问题是这里有很多样板代码,每个aditional属性需要10行。

有没有办法减少每个新物业所需的线路数量?重用getter和setter?任何类型的运行时生成器?

2 个答案:

答案 0 :(得分:1)

您可以尝试将实际值包装在一个处理所有脏工作的类中:

class WrappedUserDefault<T> {
    let key : String
    let defaultValue : T

    var value : T {
        get {
            if let value = UserDefaults.standardUserDefaults.objectForKey(key) as? T {
                return value
            } else {
                return defaultValue
            }
        }
        set {
            if let value = newValue as? AnyObject {
                UserDefaults.standardUserDefaults.setValue(value, forKey: key)
            } else {
                UserDefaults.standardUserDefaults.removeObjectForKey(key)
            }
            UserDefaults.standardUserDefaults.synchronize()
        }
    }

    init(key:String, defaultValue:T) {
        self.key = key
        self.defaultValue = defaultValue
    }
}

struct UserDefaults {
    static let standardUserDefaults = NSUserDefaults.standardUserDefaults()

    static let ready = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
    static let count = WrappedUserDefault<Int>(key: "count", defaultValue: 0)
}

然后只需要更多代码就可以了:

UserDefaults.count.value++
UserDefaults.ready.value = true
UserDefaults.ready.value

如果ready.value的详细程度困扰你,你可以稍微隐藏一下,尽管那时你又回到了拥有相当数量的复制/粘贴代码的地方:

struct UserDefaults {
    static let standardUserDefaults = NSUserDefaults.standardUserDefaults()

    private static let readyWrapper = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
    static var ready : Bool { 
        get { return readyWrapper.value } 
        set { readyWrapper.value = newValue }
    }
}

至少在这种情况下,复制/粘贴代码相当简单,因此将来不太可能需要更改。

答案 1 :(得分:0)

我更喜欢大卫的答案,但这是另一种选择。将每个变量的10行减少到5(主要是因为删除了新的行...)

struct UserDefaults {

    private static var standardUserDefaults: NSUserDefaults = {
        return NSUserDefaults.standardUserDefaults()
    }()

    //Repeate these 5 lines for all new variables, 
    //changing the as? to the proper variable type

    //Adding in a default value for the return in 
    //case the as? cast fails for any reason

    private static let propKey = "PROP"
    static var prop: Bool {
        get { return (getVar(propKey) as? Bool) ?? false }
        set { setVar(newValue, key:propKey) }
    }


    //The generic set/get
    private static func getVar(key : String) -> AnyObject?
    {
        return standardUserDefaults.objectForKey(key)
    }

    private static func setVar(newValue : AnyObject, key : String)
    {
        if(newValue is Bool)
        {
            standardUserDefaults.setBool((newValue as? Bool)!, forKey: key)
        }
            //... More cases here
        else if(newValue == nil)
        {
           standardUserDefaults.removeObjectForKey(key)
        }
        else
        {
            standardUserDefaults.setObject(newValue, forKey: key)
        }
        standardUserDefaults.synchronize()
    }
}