【问题标题】:Is there any way of sharing getter and setter through properties in Swift?有没有办法通过 Swift 中的属性共享 getter 和 setter?
【发布时间】:2016-01-28 02:04:51
【问题描述】:

我正在构建一个助手来启用对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

问题是有很多样板代码,每个附加属性我需要 10 行。

有什么方法可以减少每个新属性所需的行数?重用getter和setter?任何类型的运行时生成器?

【问题讨论】:

  • func valueForUndefinedKey(_ key: String) -> AnyObject?怎么样
  • 你可以使用枚举。在一个枚举中定义很多值,然后使用UserDefaults.get(enum.value)。没有那么优雅,但代码更少。
  • 我想过@Putz1103,但正如你所说,没那么优雅
  • @RolandasR,这样做的目的是拥有类型化的变量和良好的语法。我不明白 valueForUndefinedKey 可以如何帮助我们
  • @gfpacheco 您仍然可以将属性定义为dynamic(ObjC 中的@dynamic

标签: ios swift


【解决方案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 }
    }
}

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

【讨论】:

  • 这很有趣,谢谢你的回答,虽然我宁愿复制/粘贴到一个地方而不是每次都写.value
【解决方案2】:

我更喜欢大卫的回答,但这里有另一种选择。将每个变量的 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()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多