【问题标题】:Mapping between array of enums and a dictionary of enums枚举数组和枚举字典之间的映射
【发布时间】:2016-06-24 19:33:28
【问题描述】:

这就是我想要做的:

  1. 提供一个tableView,允许用户选择一个公式名称(一个枚举)并将其设置为默认值
  2. 在此视图中,我将勾选当前默认公式旁边的复选标记
  3. 他们选择的默认公式将决定使用哪个公式来计算 1 代表的最大量(用户可以根据较轻重量的实际举重而举起的理论量)
  4. 计算值后,用户将能够保存他们所做的提升记录、用于计算最大值的公式和计算的最大重量。
  5. 该记录将保存在 Core Data 中,其中一个实体是 Lift,它只是公式名称
  6. 我创建了一个类,我想要处理将当前默认公式提供给应用程序需要它的任何部分以及在选择新公式时设置默认值的工作。

这是我的公式名称枚举:

 enum CalculationFormula: Int {
      case Epley
      case Brzychi
      case Baechle
      case Lander
      case Lombardi
      case MayhewEtAl
      case OConnerEtAl
    }

和来自 SO 社区的 help 一起,我创建了这个类来处理 userDefaults 的管理:

class UserDefaultsManager: NSUserDefaults {

  let formulas = [CalculationFormula.Baechle, CalculationFormula.Brzychi, CalculationFormula.Epley, CalculationFormula.Lander, CalculationFormula.Lombardi, CalculationFormula.MayhewEtAl, CalculationFormula.OConnerEtAl]

  let formulaNameDictionary: [CalculationFormula : String] =
    [.Epley : "Epley", .Brzychi: "Brzychi", .Baechle: "Baechle", .Lander: "Lander", .Lombardi: "Lombardi", .MayhewEtAl: "Mayhew Et.Al.", .OConnerEtAl: "O'Conner Et.Al"]

  let userDefaults = NSUserDefaults.standardUserDefaults()

  func getPreferredFormula() -> CalculationFormula? {
    guard NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.contains("selectedFormula") else {
      print("No value found")
      return nil
    }
    guard let preferredFormula = CalculationFormula(rawValue: NSUserDefaults.standardUserDefaults().integerForKey("selectedFormula")) else {
      print("Wrong value found")
      return nil
    }
    return preferredFormula
  }

  func setPreferredFormula(formula: CalculationFormula) {
    NSUserDefaults.standardUserDefaults().setInteger(formula.rawValue, forKey: "selectedFormula")
  }

您可以看到我有一个枚举数组,按我希望它们显示在tableView 中的顺序和一个枚举字典,因此我可以让每个枚举的字符串表示形式显示在tableView 的每个单元格中。以下是我填充单元格文本标签的方法:

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("formulasCell", forIndexPath: indexPath)
    let currentFormula = formulas[indexPath.row].formulaName
    cell.textLabel?.text = currentFormula
    return cell
  }

and here's where I'm setting the checkmark anytime a cell in the tableView is selected

  func refresh() {
    let preferredFormula = defaults.getPreferredFormula()
    for index in 0 ... formulas.count {
      let indexPath = NSIndexPath(forItem: index, inSection: 0)
      if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        cell.accessoryType = preferredFormula == index ? .Checkmark : .None
      }
    }
  }

正如我在开头提到的,我需要对这个枚举做很多不同的事情,但为了让这个问题集中在一件事上,我将继续使用这个现在没有的复选标记示例创建我的 UserDefaultsManager 类后工作

问题很明显——preferredFormula 现在是一个枚举,我无法将它与 Int 的索引值进行比较——但解决方案不是。我可以获得枚举的原始值,但不能保证rawValues 与单元格indexPaths 一致。我的一些想法是:

  1. 我可能会更改枚举案例的顺序,以便它们的原始值与我将它们放在公式数组中的顺序相匹配,但这似乎很愚蠢且不可靠
  2. 我可以使用数组索引值,但这似乎同样愚蠢和不可靠
  3. 如果我只使用数组,我没有要在单元格中显示的案例的字符串表示形式

似乎将数组和字典一起使用是可行的,但我能想到的最好办法是创建另一个将枚举映射到 Ints 的字典,但这会遇到我刚刚列出的相同问题。

如果有人能提供任何指导,我们将不胜感激。

【问题讨论】:

  • 为什么需要将CalculationFormula 作为Int 值的枚举?你不能使用来自String 值的枚举并将它们的名称映射到枚举中而不是制作一个单独的字典吗?然后您可以使用数组索引来跟踪哪个是preferredFormula
  • 我将它们设为Int,以便在将复选标记设置为默认值时将它们与tableView 单元格的indexPath.row 匹配。我无法以其他任何方式做到这一点。

标签: ios arrays swift enums


【解决方案1】:

您似乎使事情变得比实际需要的复杂一些。

首先,您可以为枚举使用 String 原始值并避免关联字典:

enum CalculationFormula: String {
    case Epley = "Epley"
    case Brzychi = "Brzychi"
    case Baechle = "Baechle"
    case Lander  = "Lander"
    case Lombardi = "Lombardi"
    case MayhewEtAl = "Mayhew Et.Al."
    case OConnerEtAl = "O'Conner Et.Al"
}

其次,您的UserDefaultsManager 不需要继承 NSUserDefaults,它只是一些实用功能。此外,您在getPreferredFormula 上做了很多您不需要的检查。我建议重写该类以使用这样的计算属性:

class UserDefaultsManager {

    static let sharedInstance = UserDefaultsManager()

    private var defaultsFormula: CalculationFormula?

    var preferredFormula: CalculationFormula? {

        get {
            if self.defaultsFormula == nil {
                let defaults = NSUserDefaults.standardUserDefaults()
                if let defaultValue = defaults.objectForKey("selectedFormula") as? String {
                    self.defaultsFormula = CalculationFormula(rawValue: defaultValue)
                }
            }
            return self.defaultsFormula
        }

        set {   
            self.defaultsFormula = newValue
            let defaults = NSUserDefaults.standardUserDefaults()
            if (self.defaultsFormula == nil) {
                defaults.removeObjectForKey("selectedFormula")
            } else {
                defaults.setObject(self.defaultsFormula!.rawValue, forKey: "selectedFormula")
            }
        } 
    }
}

我已将班级设为单例;尽管这可能会对可测试性产生影响,但它简化了在多个地方更改默认值时可能出现的问题。

设置/清除复选标记的适当位置是cellForRowAtIndexPath,以便正确处理单元重用。此代码假定formulasCalculationFormula 的数组:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("formulasCell", forIndexPath: indexPath)
    let currentFormula = formulas[indexPath.row]
    cell.textLabel?.text = currentFormula.rawValue

    let preferredFormula = UserDefaultsManager.sharedInstance.preferredFormula
    cell.accessoryType = currentForumula == preferredFormula ? .Checkmark : .None
    return cell
}

【讨论】:

  • 谢谢你的建议,保罗。它现在有效,但我有几个问题。 1)是否有必要让班级成为单身人士?我读过一些东西,听起来像是在实例化 NSUserDefaults 时,Swift 足够聪明,不会在下次调用它时再次实例化它。 2) 为什么必须在cellForRowAtIndexPath 中设置/清除复选标记代码?当我在那里拥有它时,我必须添加 tableView.reloadData() 才能让它出现并且它不平滑,而我从 Ray Wenderlich 教程中采用的 refresh() 方法非常平滑并且没有视觉闪烁。
  • 您也可以使用刷新方法,但您应该始终在 cellForRowAtIndexPath 中设置它。该类不必是单例,但如果不是,则在多个地方使用 UserDefaultsManager 时需要小心,因为该属性可能不会反映更改的值。 NSUserDefaults.standardUserDefaults 是一个单例,但这并不意味着 defaultsForumula 将在多个 UserDefaultsManager 实例中更新
猜你喜欢
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 2016-09-10
  • 1970-01-01
相关资源
最近更新 更多