我知道有很多关于编译时错误 Type of expression is ambiguous without more context
的问题,但是我读了很多,似乎不明白为什么我的会出现这种情况。
首先,我有:
protocol ExpensePeriod: AnyObject, Identifiable, Hashable {
associatedtype Period: ExpensePeriod
var type: Calendar.Component { get set }
var interval: DateInterval { get set }
var start: Date { get }
var end: Date { get }
var expenses: FetchRequest<Expense> { get }
static func array(from startDate: Date, to endDate: Date) -> [Period]
init(from date: Date)
}
然后:
extension ExpensePeriod {
var start: Date { interval.start }
var end: Date { interval.end }
var expenses: FetchRequest<Expense> {
FetchRequest<Expense>(
entity: Expense.entity(),
sortDescriptors: [NSSortDescriptor(key: "datetime", ascending: false)],
predicate: NSPredicate(
format: "datetime > %@ AND datetime < %@",
argumentArray: [start, end]
)
)
}
static func array(of timeComponent: Calendar.Component, from startDate: Date, to endDate: Date) -> [Self] {
var currentDate = startDate
var array = [Self(from: currentDate)]
while !Calendar.current.dateInterval(of: timeComponent, for: currentDate)!.contains(endDate) {
currentDate = Calendar.current.date(byAdding: timeComponent, value: 1, to: currentDate)!
array.append(Self(from: currentDate))
}
return array
}
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.interval == rhs.interval
}
func hash(into hasher: inout Hasher) {
hasher.combine(interval)
}
}
接下来:
final class ExpenseYear: ExpensePeriod {
typealias Period = ExpenseYear
var type: Calendar.Component
var interval: DateInterval
var year: Int { Calendar.current.component(.year, from: interval.start) }
var expenseMonths: [ExpenseMonth] {
return ExpenseMonth.array(from: start, to: end)
}
static func array(from startDate: Date, to endDate: Date) -> [ExpenseYear] {
array(of: .year, from: startDate, to: endDate)
}
init(from date: Date) {
self.type = .year
self.interval = Calendar.current.dateInterval(of: type, for: date)!
}
}
现在是主要的SwiftUI视图:
struct ListView: View {
@Environment(\.managedObjectContext) private var managedObjectContext
@FetchRequest(
entity: Expense.entity(),
sortDescriptors: [NSSortDescriptor(key: "datetime", ascending: false)]
) var expenses: FetchedResults<Expense>
@State private var showingNewExpenseSheet = false
@State private var showingPreferencesSheet = false
private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "YYYY MMM"
return formatter
}
var body: some View {
NavigationView {
List {
ForEach(ExpenseYear.array(from: expenses.last!, to: expenses.first!)) { expenseYear in
ForEach(expenseYear.expenseMonths) { expenseMonth in
MonthlyListView(expenseMonth)
}
Text("\(0)")
}.onDelete(perform: deleteExpenseItem)
}
.navigationBarTitle("Expenses")
.navigationBarHidden(true)
}
}
func deleteExpenseItem(at offsets: IndexSet) {
for index in offsets {
let expense = expenses[index]
managedObjectContext.delete(expense)
}
do {
try managedObjectContext.save()
} catch {
print("Wasn't able to save after delete due to \(error)")
}
}
}
struct MonthlyListView: View {
@Environment(\.managedObjectContext) private var managedObjectContext
var expenseFetchRequest: FetchRequest<Expense>
var expenses: FetchedResults<Expense> {
expenseFetchRequest.wrappedValue
}
let expenseMonth: ExpenseMonth
init(_ month: ExpenseMonth) {
self.expenseMonth = month
self.expenseFetchRequest = month.expenses
}
var body: some View {
Section(header: Text("\(expenseMonth.month)")) {
ForEach(expenses) { expense in
ExpenseRowItemView(expense)
}
}
}
}
ExpenseRowItemView
仅显示各种日期/备注项目。
Type of expression is ambiguous without more context
似乎发生在ForEach(ExpenseYear.array(from: expenses.last!, to: expenses.first!))
。我使用的是Xcode 12 beta。谢谢你的帮助。
(如果您想知道我为什么要经历所有这些麻烦来渲染一份支出清单:我曾经有一个函数,它遍历每个支出的日期,并构建嵌套的年份和月份结构,以便SwiftUI进行呈现(使用Section等)。但我认为这不是可扩展/高效的方法,因为每次渲染视图时都会调用此功能,击中Core Data中的每个条目,所以我想让每个月度列表处理其自己的FetchRequest及其自己的日期边界,这也将使"选择一个月份以查看该月份交易清单"之类的动态视图更容易。请告诉我是否有更好的方法。)