如何按创建 UITableViewCell 时计算的值对 UITableView 进行排序?



我的应用程序中有一个UITableView,它显示了NSFetchedResultsControllerLiftEvent类型的NSManagedObjects的一长串。但是,显示的值之一不是存储属性,它是通过在创建UITableViewCell的视图模型时对对象调用方法(在extension中(来计算的:

class LiftLogTableViewCell: UITableViewCell {
    @IBOutlet weak var liftName: UILabel!
    @IBOutlet weak var liftDetails: UILabel!
    @IBOutlet weak var liftDate: UILabel!
    @IBOutlet weak var oneRepMaxWeight: UILabel!
    @IBOutlet weak var unit: UILabel!
    @IBOutlet weak var formula: UILabel!
    var liftWeight: String!
    var repetitions: String!
    struct ViewData {
        let liftName: String
        let liftWeight: Double
        let repetitions: Int
        let liftDate: String
        let oneRepMaxWeight: Double
        let unit: String
        let formula: String
    }
    var viewData: ViewData! {
        didSet {
            liftName!.text = viewData.liftName
            liftWeight = String(viewData.liftWeight)
            repetitions = String(viewData.repetitions)
            let formatter = StringFormatter()
            let formattedWeightLifted = formatter.formatForDisplay(viewData.liftWeight)
            liftDetails!.text = "(formattedWeightLifted) @ (viewData.repetitions)"
            liftDate!.text = "on (viewData.liftDate)"
            oneRepMaxWeight!.text = "(viewData.oneRepMaxWeight)"
            unit!.text = viewData.unit
            formula!.text = viewData.formula
        }
    }
}
extension LiftLogTableViewCell.ViewData {
    init(liftEvent: LiftEvent) {
        self.liftName = liftEvent.lift.liftName
        // liftEvent.calculatOneRepMax() uses two stored properties of the LiftEvent to calculate the value
        let oneRepMax = liftEvent.calculateOneRepMax() 
        if liftEvent.liftWeight.unit.symbol == UserDefaults.weightUnit() {
            self.liftWeight = liftEvent.liftWeight.value
            self.oneRepMaxWeight = oneRepMax.value
            self.unit = oneRepMax.unit.symbol
                } else {
                    let convertedLiftWeight = ConvertWeightService().convertToOtherUnit(weight: liftEvent.liftWeight)
                    self.liftWeight = convertedLiftWeight.value
                    let convertedMaxWeight = ConvertWeightService().convertToOtherUnit(weight: oneRepMax)
                    self.oneRepMaxWeight = convertedMaxWeight.value
                    self.unit = convertedMaxWeight.unit.symbol
        }
        self.repetitions = Int(liftEvent.repetitions)
        self.formula = liftEvent.formula.formulaName
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let formattedDate = dateFormatter.string(from: liftEvent.date as Date)
        self.liftDate = "(formattedDate)"
    }
}

我已经做了我的功课,发现了两年前的一个线程和四年多前的另一个线程,说使用 NSFecthedResultsController 时无法完成,但 Swift 变化如此之快,以至于我想知道现在是否有可能。我已经阅读了Apple的文档,但我看不到一种方法,但是我对这个API很陌生。

有没有办法用NSFetchedResultsController做到这一点,还是我必须放弃它并使用一个简单的数组?

swift 没有什么神奇之处,它允许你创建一个按未存储在核心数据中的属性排序的 fetchedResultsController。有三种可能的解决方案:

  1. 按具有相同顺序的其他属性排序。 例如,您可以按date排序,然后按day显示,即使day不是属性,它也是来自date的派生属性。您甚至可以将day用作sectionNameKeyPath
  2. 将值存储为常规属性。 如果它派生自其他属性,则必须在更新其他属性时更新它。
  3. 执行
  4. 提取后执行内存中排序。

1 是最好的解决方案,但我不了解您的模型是否可能。 如果不可能,我会推荐2。 通常,最好只从一个位置更新模型,因此添加代码以同步派生属性不应如此繁琐。

最新更新