【问题标题】:Swift Struct extensionSwift 结构扩展
【发布时间】:2019-06-15 10:36:44
【问题描述】:

我有一个设置结构,它在UserDefaults 中存储了数百个设置。 代码如下:

struct Settings {

public enum key: String
{
    case mySetting = "mySetting"
    ...
    ...

}

 public var mySetting: Bool {
    get {
        return UserDefaults.standard.bool(forKey: key.mySetting.rawValue)
    }

    set (newValue) {
        return UserDefaults.standard.set(newValue, forKey: key.mySetting.rawValue)
    }
}

 ....
 ....
}

我想扩展它。我想获取在对等设备上运行的应用程序的另一个实例的设置并将其存储为Dictionary。 mySetting 他们必须从 dictionary 而不是 UserDefaults 返回 key.mySetting key 的值。但是如果没有连接对等设备,那么它应该返回UserDefaults中的值。

我想知道如何扩展 Settings 结构(或者如果需要将其更改为 class)来实现此功能,而无需在代码中的数百个位置放置“if then else”。

我在数百个地方这样做:

 var settings = Settings()

或者

 let settings = Settings()

最好有一些自动提取正确设置字典来查找的结构。

编辑:正如我所说,并非所有返回类型都可以简单,这使工作变得更加困难。一些返回类型是枚举、一些字典、一些数组。正如一些人建议使用一种返回 Any? 的统一方法,例如,在我使用返回类型的地方,这项工作会更加困难。

  public var microphone: Microphone {
    get {
        if let mic = Microphone.init(rawValue: UserDefaults.standard.integer(forKey: key.microphone.rawValue)) {
            return mic
        } else {
            return .auto
        }
    }

    set (newValue) {
        UserDefaults.standard.set(newValue.rawValue, forKey: key.microphone.rawValue)
    }
}

【问题讨论】:

  • 你能添加到你的设置结构的代码吗?
  • 代码只是设置的,我刚刚更新了。
  • 您的代码的问题是默认值中的每个设置都通过不同的方法;例如,public var mySetting 仅处理 mySetting 默认键。您应该通过 one 方法传递所有内容。
  • @matt 问题不是所有设置变量/方法都具有相同的返回类型。一些返回类型是枚举,我在这些方法中做了艰苦的工作。一种方法怎么能解决所有问题?如果我有一个返回 Any? 的方法,那么在我使用该方法的地方,我将需要重做努力。上面的示例(代码已编辑)。
  • 这就是泛型存在的原因。

标签: ios swift userdefaults


【解决方案1】:

我会为字典添加一个可选属性,然后使用一对 get 和 set 函数使用字典或 UserDefaults

var peerDevice: [String: Any]?

func setting(forKey key: Key) -> Any? {
    if let dictionary = peerDevice {
        return dictionary[key.rawValue]
    }
    return UserDefaults.standard.value(forKey: key.rawValue)
}

mutating func set(_ value: Any, forKey key: Key) {
    if peerDevice != nil {
        peerDevice?[key.rawValue] = value
    } else {
        UserDefaults.standard.set(value, forKey: key.rawValue)
    }        
}

使用原始值的枚举的包装方法示例

mutating func setEnum<T>(_ value: T, forKey key: Key) where T: RawRepresentable {
    set(value.rawValue, forKey: key)
}

func setting<T>(forKey key: Key, andEnumType: T.Type) -> T? where T: RawRepresentable {
    if let value = setting(forKey: key) as? T.RawValue {
        return T.init(rawValue: value)
    }
    return nil
}

我冒昧地将枚举从 key 重命名为 Key

那就这样用吧

var settings = Settings()

settings.setSetting(true, forKey: .mySetting)

if let flag = settings.setting(forKey: .mySetting) as? Bool {
    print(flag)
}

settings.setEnum(Microphone.mic2, forKey: .mic)

if let mic = settings.setting(forKey: .mic, andEnumType: Microphone.self) {
    print(mic)
}

【讨论】:

  • 我编辑了代码,让我知道如何处理设置中所有可能的返回类型。可能是我遗漏了一些东西,但是如果您有复杂的返回类型(例如枚举),这段代码是否仍然可以无缝运行?
  • @DeepakSharma 将第一个方法视为获取和设置值的基本方法,然后您可以添加包装器方法以用于不同的类型。我为我的答案添加了一个枚举
  • 感谢您的回答。只是一个简单的问题,将设置作为结构与类,因为方法太多,将设置作为类而不是结构有意义吗?
  • 没关系,我可能会使用结构体。既然你只想要,至少我假设是这样,你应该考虑将其设置为 Singleton 的一个实例。
  • @DeepakSharma 对于大多数类型,您应该能够使用我使用 Any 的基本函数,也许这不适用于 Array 和 Dictionary 这样的集合,但您不必实现那么多额外的函数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2023-03-30
  • 2012-03-30
相关资源
最近更新 更多