如何根据创建 UITableViewCell 时计算的值对 UITableView 进行排序?
How can I sort a UITableView by a value that's calculated when a UITableViewCell is created?
我的应用程序中有一个 UITableView
,它显示 NSFetchedResultsController
中 LiftEvent
类型的一长串 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)"
}
}
我已经完成了我的作业,找到了四年前的 from two years ago and another thread 说使用 NSFecthedResultsController
时无法完成,但是 Swift 正在改变很快,我想知道现在是否可能。我已经阅读了 Apple 的文档,但我看不到这样做的方法,但我对此很陌生 API。
有没有办法用 NSFetchedResultsController
做到这一点,还是我必须放弃它并使用一个简单的数组?
swift 并没有什么神奇之处,它允许您创建一个按未存储在核心数据中的属性排序的 fetchedResultsController。共有三种可能的解决方案:
- 按具有相同顺序的不同 属性 排序。例如,您可以按
date
排序,然后按 day
显示,即使 day
不是 属性,而是从 date
派生的 属性 .您甚至可以将 day
用作 sectionNameKeyPath
.
- 将值存储为常规 属性。如果它是从其他属性派生的,那么您必须在其他属性更新时更新它。
- 获取后进行内存排序。
1 是最好的解决方案,但我不了解您的模型,不知道是否可行。如果不可能,我会推荐 2。一般来说,只从一个地方更新模型是一种很好的做法,因此添加代码来同步派生属性应该不会那么繁重。
我的应用程序中有一个 UITableView
,它显示 NSFetchedResultsController
中 LiftEvent
类型的一长串 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。共有三种可能的解决方案:
- 按具有相同顺序的不同 属性 排序。例如,您可以按
date
排序,然后按day
显示,即使day
不是 属性,而是从date
派生的 属性 .您甚至可以将day
用作sectionNameKeyPath
. - 将值存储为常规 属性。如果它是从其他属性派生的,那么您必须在其他属性更新时更新它。
- 获取后进行内存排序。
1 是最好的解决方案,但我不了解您的模型,不知道是否可行。如果不可能,我会推荐 2。一般来说,只从一个地方更新模型是一种很好的做法,因此添加代码来同步派生属性应该不会那么繁重。