【问题标题】:SwiftUI: ObservableObject doesn't work with fetchRequest initSwiftUI:ObservableObject 不适用于 fetchRequest init
【发布时间】:2020-10-26 03:17:27
【问题描述】:

我的 DateView 中有一个像这样声明的 ObservableObject:

import SwiftUI

    class SelectedDate: ObservableObject {
        @Published var selectedMonth: Date = Date()
        
        var startDateOfMonth: Date {
            let components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
            let startOfMonth = Calendar.current.date(from: components)!
            return startOfMonth
        }
    
        var endDateOfMonth: Date {
            var components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
            components.month = (components.month ?? 0) + 1
            let endOfMonth = Calendar.current.date(from: components)!
            return endOfMonth
        }
    }

struct DateView: View {
// other code
}

我可以像这样在其他视图中访问 startDateOfMonth 和 endDateOfMonth:

Text("\(self.selectedDate.startDateOfMonth)")

但是当我尝试在 TransactionsListView 的 fetchRequest 初始化程序中使用 ObservableObject 中的这些变量时,我遇到了问题:

    import SwiftUI
    
    struct TransactionsListView: View {
    
    @Environment(\.managedObjectContext) var managedObjectContext
        var fetchRequest: FetchRequest<NPTransaction>
        var transactions: FetchedResults<NPTransaction> { fetchRequest.wrappedValue }
    @EnvironmentObject var selectedDate: SelectedDate

    // other code
            init() {
                    fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [
                        NSSortDescriptor(keyPath: \NPTransaction.date, ascending: false)
                    ], predicate: NSPredicate(format: "date >= %@ AND date < %@", self.selectedDate.startDateOfMonth as NSDate, self.selectedDate.endDateOfMonth as NSDate))
            }
    
    var body: some View {
    // other code
    }
    }

我收到一个错误:

在初始化之前使用的变量“self.fetchRequest”

我做错了什么?我试图在没有 self 的情况下在 init 中使用这些变量。同样的错误。它起作用的唯一方法是,如果这些 startDateOfMonth 和 endDateOfMonth 不在 ObservableObject 中,而是作为祖先视图中的一个变量,我通过 fetchRequest init 作为参数传递给我的视图。但是我很少有这样的视图,并且想使用 ObservableObject,而不是一直将相同的参数传递给子视图。

【问题讨论】:

  • 您能说明如何在初始化之前声明selectedDate 吗?
  • selectedDate 在另一个视图 (DateView) 中的 class SelectedDate: ObservableObject {...} 中声明。我尝试在我有 fetchRequest init 的 TransactionsListView 中使用它。我不能在 init 中使用它,但我可以在 body 中使用它作为 Text("\(self.selectedDate.startDateOfMonth)") 例如没有问题。我已经用更多细节更新了我的问题。

标签: swift core-data swiftui observableobject fetchrequest


【解决方案1】:

问题是您不能在init() 中使用@EnvironmentObject。这里可能的选项是将EnvironmentObject 作为参数传递给视图。然后在 init 中使用该参数。这是视图的构造函数,然后您可以使用局部变量selectedDate访问开始和结束时间。

init(selectedDate : SelectedDate) 
{
   //now you can access selectedDate here and use it in FetchRequest
   fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \NPTransaction.date, ascending: false)], predicate: NSPredicate(format: "date >= %@ AND date < %@", selectedDate.startDateOfMonth as NSDate, selectedDate.endDateOfMonth as NSDate))
}

在调用该视图的地方,将EnvironmentObject 作为参数传递。

                                    //Declared as Environment Object
TransactionsListView(selectedDate : self.selectedDate)

【讨论】:

  • 非常感谢。我想我可以传递这样的参数:TransactionsListView(startDateOfMonth: self.selectedDate.startDateOfMonth, endDateOfMonth: self.selectedDate.endDateOfMonth),但你的版本更好! :)
【解决方案2】:

Swift 保证所有属性都在 init 之后初始化。

当你访问对象属性时,假设对象已经被初始化,而你在初始化过程中访问它时不是这样。

当你初始化fetchRequest时,你会访问self.selectedDate(无论你是否添加self,编译器都一样),这表明self被初始化了,这意味着fetchRequest,作为其中之一self 的属性,可以使用了。因此编译器错误:

在初始化之前使用的变量“self.fetchRequest”

使fetchRequest 计算或惰性属性应该可以工作。 (对@FetchRequest不太熟悉)

希望这会有所帮助。

【讨论】:

  • 谢谢,但是怎么办呢?您的意思是我不应该将 fetchrequest 放在 init 中,而是将其设为 var 或惰性 var?我使用 init 是因为我发现它在一些教程中有效。还在学习 Swift 和 SwiftUI 和 inits 是我还不是很了解的东西
  • 是的,在计算或惰性变量的范围内,您可以访问 self. Swift 有非常严格的两阶段初始化过程。在初始化之后做事情通常更容易,而不是在初始化期间。你应该可以在网上找到很多关于计算的、惰性的、两阶段初始化的例子。
【解决方案3】:

您可以将其作为参数传递给视图:

import SwiftUI

struct TransactionsListView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest var transactions: FetchedResults<NPTransaction>

    init(selectedDate: SelectedDate) {
        _transactions = FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \NPTransaction.date, ascending: false)], predicate: NSPredicate(format: "date >= %@ AND date < %@", selectedDate.startDateOfMonth as NSDate, selectedDate.endDateOfMonth as NSDate))
    }

    var body: some View {
    // other code
    }
}

selectedDate 存储为超级视图中的@State,并使用当前值重新创建TransactionsListView

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 2014-04-30
    相关资源
    最近更新 更多