Swiftui 在父视图中使用@FetchRequest结果
我试图把一些组件抽象成更小的部分。为此,我创建了以下列表:Swiftui 在父视图中使用@FetchRequest结果,swiftui,fetchrequest,Swiftui,Fetchrequest,我试图把一些组件抽象成更小的部分。为此,我创建了以下列表: struct ArticleList:视图{ var fetchRequest:fetchRequest var结果:FetchedResults{fetchRequest.wrappedValue} init(){ fetchRequest=fetchRequest( 实体:Article.entity(), sortDescriptors:[] ) } var body:一些观点{ ForEach(results){article
struct ArticleList:视图{
var fetchRequest:fetchRequest
var结果:FetchedResults{fetchRequest.wrappedValue}
init(){
fetchRequest=fetchRequest(
实体:Article.entity(),
sortDescriptors:[]
)
}
var body:一些观点{
ForEach(results){article in
文本(article.name???)
}
}
}
现在我有了一个容器,它将显示列表组件,如果子组件内的条件满足,还将显示一些附加内容:
struct容器:视图{
var body:一些观点{
让articleList=ArticleList2()
返回组{
如果articleList.results.isEmpty{
文本(“添加”)
}
标记名
}
}
}
现在我的问题是代码崩溃,出现以下异常:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
通过控制台进一步调试,我得到了以下反馈:
(lldb) po self.results
error: warning: couldn't get required object pointer (substituting NULL): Couldn't load 'self' because its value couldn't be evaluated
调试po self.fetchRequest
有效,它包含fetchRequest
实例的一个实例po self.fetchRequest.wrappedValue提供与上述self.results
相同的错误
有人知道为什么这段代码会崩溃,以及可能的解决方法是什么吗
谢谢。您的获取请求不起作用,因为在您创建和使用ArticleList
视图时,还没有可用的托管对象上下文
无论如何。。。找到下面修改过的(我尽量减少更改)您的代码。使用Xcode 11.4/iOS 13.3进行测试
struct ArticleList: View {
// always keep View memebers private to safe yourself from misconcept
private var fetchRequest: FetchRequest<Article>
private var results: FetchedResults<Article> { fetchRequest.wrappedValue }
private var reportEmpty: () -> ()
init(_ onEmpty: @escaping () -> ()) {
reportEmpty = onEmpty
// FetchRequest needs @Environment(\.managedObjectContext) which is not available (!) yet
fetchRequest = FetchRequest<Article>(
entity: Article.entity(),
sortDescriptors: []
)
}
var body: some View {
// here (!) results are valid, because before call body SwiftUI executed FetchRequest
if self.results.isEmpty {
self.reportEmpty()
}
return Group {
ForEach(results, id: \.self) { article in
Text(article.name ?? "")
}
}
}
}
struct Container: View {
@State private var isEmpty = false
var body: some View {
return Group {
if self.isEmpty { // use view state for any view's conditions
Text("Add")
}
ArticleList { // View must live only in view hierarchy !!
DispatchQueue.main.async {
self.isEmpty = true
}
}
}
}
}
struct ArticleList:视图{
//始终保持查看成员的隐私,以避免误解
私有变量fetchRequest:fetchRequest
私有变量结果:FetchedResults{fetchRequest.wrappedValue}
私有变量reportEmpty:()->()
init(onEmpty:@escaping()->()){
reportEmpty=onEmpty
//FetchRequest需要@Environment(\.managedObjectContext),但它还不可用(!)
fetchRequest=fetchRequest(
实体:Article.entity(),
sortDescriptors:[]
)
}
var body:一些观点{
//这里(!)的结果是有效的,因为在调用体之前SwiftUI执行了FetchRequest
如果self.results.isEmpty{
self.reportEmpty()
}
返回组{
ForEach(results,id:\.self){article in
文本(article.name???)
}
}
}
}
结构容器:视图{
@State private var isEmpty=false
var body:一些观点{
返回组{
如果self.isEmpty{//则对任何视图的条件使用视图状态
文本(“添加”)
}
ArticleList{//视图必须仅存在于视图层次结构中!!
DispatchQueue.main.async{
self.isEmpty=true
}
}
}
}
}
虽然@Asperi的解决方案有效,但我现在确实以不同的方式实现了它
我将一个闭包传递给文章列表
,如果按下按钮
,则执行该回调。只有当文章列表
为空时,按钮
才可用,但现在文章列表
负责显示按钮(这使它对我来说更易于重用:
struct ArticleList:视图{
var fetchRequest:fetchRequest
var结果:FetchedResults{fetchRequest.wrappedValue}
让onCreate:(()->Void)
初始化(onCreate:@escaping(()->Void)){
fetchRequest=fetchRequest(
实体:Article.entity(),
sortDescriptors:[]
)
self.onCreate=onCreate
}
var body:一些观点{
团体{
如果结果是空的{
按钮(操作:onCreate){
文本(“添加”)
}
}
ForEach(results){article in
文本(article.name???)
}
}
}
}
结构容器:视图{
var body:一些观点{
文章列表(onCreate:onCreate)
}
func onCreate(){
//在容器内创建项目
}
}
虽然我可以确认这是可行的,但在视图构建内部状态发生更改时感觉不对劲。这意味着,如果状态发生更改,视图层次结构将构建两次。这也将触发多个提取请求以执行。@TobiasTom,延迟刷新是常规做法,有些操作甚至在没有uch方法(实际上相当于setNeedsLayout
或setNeedsDisplay
。SwiftUI处理此类情况,不会重新呈现未更新的视图。但关于获取数据,这是您的责任,不应依赖或影响显示视图。其他一切都由您决定。