1

只是在思考如何构建一些基于层次结构自动生成键的 UserDefaults 的语言。这让我想知道......是否可以像这样同时定义和实例化一个类型?

let myUserSettings = {

    let formatting = {

        var lastUsedFormat:String

    }
}

let lastUsedFormat = myUserSettings.formatting.lastUsedFormat

注意:我不能使用静态,因为我特别需要实例化,因此具有静态成员的嵌套结构/类不适用于我的情况。

这是我能想到的最接近的东西,但我讨厌我必须创建初始化程序来设置成员。我希望有一些不那么冗长的东西。

class DefaultsScope {

    init(_ userDefaults:UserDefaults){
        self.userDefaults = userDefaults
    }

    let userDefaults:UserDefaults

    func keyForSelf(property:String = #function) -> String {
        return "\(String(reflecting: self)).\(property)"
    }
}

let sharedDefaults = SharedDefaults(UserDefaults(suiteName: "A")!)
class SharedDefaults : DefaultsScope {

    override init(_ userDefaults:UserDefaults){
        formatting = Formatting(userDefaults)
        misc       = Misc(userDefaults)
        super.init(userDefaults)
    }

    let formatting:Formatting
    class Formatting:DefaultsScope {

        let maxLastUsedFormats = 5

        fileprivate(set) var lastUsedFormats:[String]{
            get { return userDefaults.stringArray(forKey:keyForSelf()) ?? [] }
            set { userDefaults.set(newValue, forKey:keyForSelf()) }
        }

        func appendFormat(_ format:String) -> [String] {

            var updatedListOfFormats = Array<String>(lastUsedFormats.suffix(maxLastUsedFormats - 1))
            updatedListOfFormats.append(format)
            lastUsedFormats = updatedListOfFormats

            return updatedListOfFormats
        }
    }

    let misc:Misc
    class Misc:DefaultsScope {

        var someBool:Bool{
            get { return userDefaults.bool(forKey:keyForSelf()) }
            set { userDefaults.set(newValue, forKey:keyForSelf()) }
        }
    }
}

那么有没有更简单的方法呢?

4

4 回答 4

1

免责声明:这可能只是一个抽象的解决方案,不应该在现实生活中使用:)

enum x {
  enum y {
    static func success() {
      print("Success")
    }
  }
}
x.y.success()

更新:对不起,伙计们,我不能停止实验。这个看起来很糟糕:)

let x2= [
  "y2": [
    "success": {
      print("Success")
    }
  ]
]
x2["y2"]?["success"]?()

更新 2:再试一次,这次是元组。而且由于元组必须至少有两个值,所以我不得不在其中添加一些假人。此外,元组不能具有变异函数。

let x3 = (
  y3: (
    success: {
      print("Success")
    },
    failure: {
      print("Failure")
    }
  ),
  z3: 0
)
x3.y3.success()
于 2018-03-14T22:09:22.523 回答
0

你不能有那种结构,但你不能从 x 内部访问 y,因为 y 只在 x 的范围内可见,成功在 y 的范围内也是如此。您无法从外部访问它们

另一种选择是具有像这样的高阶函数,它返回可调用的闭包。

let x = {
            {
                {
                    print("Success")
                }
            }
        }

let y = x()
let success = y()
success()

或者

x()()()

userdefaults 的高阶函数在现实世界中的用法可能是这样的,

typealias StringType = (String) -> ((String) -> Void)
typealias IntType = (String) -> ((Int) -> Void)
typealias BoolType = (String) -> ((Bool) -> Void)

typealias StringValue = (String) -> String?
typealias IntValue = (String) -> Int?
typealias BoolValue = (String) -> Bool?

func userDefaults<T>(_ defaults: UserDefaults) -> (String) -> ((T) ->  Void) {
    return { key in
        return { value in
            defaults.setValue(value, forKey: key)
        }
    }
}

func getDefaultsValue<T>(_ defaults: UserDefaults) -> (String) -> T? {
    return { key in
        return defaults.value(forKey: key) as? T
    }
}

let setStringDefaults: StringType  = userDefaults(.standard)
setStringDefaults("Name")("Jack Jones")
setStringDefaults("Address")("Australia")

let setIntDefaults: IntType = userDefaults(.standard)
setIntDefaults("Age")(35)
setIntDefaults("Salary")(2000)

let setBoolDefaults: BoolType = userDefaults(.standard)
setBoolDefaults("Married")(false)
setBoolDefaults("Employed")(true)

let getStringValue: StringValue = getDefaultsValue(.standard)
let name = getStringValue("Name")
let address = getStringValue("Address")

let getIntValue: IntValue = getDefaultsValue(.standard)
let age = getIntValue("Age")
let salary = getIntValue("Salary")

let getBoolValue: BoolValue = getDefaultsValue(.standard)
let married = getBoolValue("Married")
let employed = getBoolValue("Employed")

我不确定你是否喜欢这种模式,但它有一些很好的用例,如下所示,setStringDefaults 你可以将字符串值设置为字符串键,并且它们都是类型安全的。

您可以为您的用例扩展它。但是,您也可以使用 struct 并使用命令式代码,这可能更容易理解。我也看到了这方面的美。

于 2018-03-14T22:38:21.723 回答
0

你试试嵌套一些 swiftstructs怎么样?

struct x {
    struct y {
        static func success() {
            print("success")
        }
    }
}

x.y.success()    
于 2018-03-14T22:45:14.407 回答
0

好吧,我想我已经想通了。第一个类可以放入您用于所有应用程序的一些公共库中。

class SettingsScopeBase {

    private init(){}

    static func getKey(setting:String = #function) -> String {
        return "\(String(reflecting:self)).\(setting)"
    }
}

下一部分是一对类:

  1. 您定义要使用的用户默认实例的“范围”类(以及您可能希望为此特定设置实例指定的任何其他内容)
  2. 定义您的设置的实际层次结构

这是第一个。我正在为我的应用程序与其扩展程序之间的共享设置进行设置:

class SharedSettingsScope : SettingsScopeBase{
    static let defaults = UserDefaults(suiteName: "group.com.myco.myappgroup")!
}

最后,这是您“设置”层次结构以及实现属性主体的方式。

class SharedSettings:SharedSettingsScope{

    class Formatting:SharedSettingsScope{

        static var groupsOnWhitespaceOnlyLines:Bool{
            get { return defaults.bool(forKey: getKey()) }
            set { defaults.set(newValue, forKey: getKey()) }
        }
    }
}

这就是你如何使用它们......

let x = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// x = false

SharedSettings.Formatting.groupsOnWhitespaceOnlyLines = true

let y = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// y = true

我将看看我是否可以进一步改进/优化它,但这非常接近我想要的位置。没有硬编码的字符串、由使用它们的层次结构定义的键,并且只在一个地方设置特定的 UserDefaults 实例。

于 2018-03-14T23:53:45.820 回答