问题
I am doing a CoreData fetch inside my init()
method of the View. I am not using FetchRequest in SwiftUI, as I need a predicate based on a parameter which is send to the View aswell. Using that parameter in the @FetchRequest will cause an error, as the variable has not been initialized.
I am doing following fetch Request inside the init()
//FetchRequest
let fetch : NSFetchRequest<Article>
self.articleRows = [Article]()
fetch = Article.fetchRequest() as! NSFetchRequest<Article>
fetch.predicate = NSPredicate(format: "type == %d", self.type)
do {
self.articleRows = try NSManagedObjectContext.current.fetch(fetch)
} catch
{
}
That is working fine. I am displaying all my data inside a ForEach
loop.
ForEach(self.articleRows, id:\.self) { article in
However, when I am deleting an entity from my context I need to refresh the view to display the changes. On delete action I toggle a @State
variable, to refresh the view. That works, however the entity is still inside my Array. Thats due to the fact that init()
is not called again and the fetch request is not made again. If init()
would be called, the deleted entity wouldn't be there anymore.
What is the best approach here? How can I refetch my CoreData entities.
My current solution: I am currently using a Binding
inside my Fetch view. If I make changes I toggle that binding and my parent view reloads. The will cause my child view (fetch View) to reload aswell and the fetch request is made again. Is that the best way? Any simpler solution for that?
回答1:
So, I found a way of solving my problem.
What was the problem?
The View was not updating because I wasn't using FetchRequest property wrapper, because I need a instance variable in that FetchRequest. So I need to do the Fetching inside my Init()
method. But what I did was, I just fetched my items once in the init()
and that won't be updated unless the parent with is reloaded.
How to solve it without annoying parent update?
Instead of doing a manual fetch only once in the init()
I used a FetchRequest and initialized it in the init(), so it still behaves as FetchRequest property wrapper, like an Observable Object.
I declared it like that:
@FetchRequest var articleRows : FetchedResults<Article>
And inside the init()
//Here in my predicate I use self.type variable
var predicate = NSPredicate(format: "type == %d", self.type)
//Intialize the FetchRequest property wrapper
self._articleRows = FetchRequest(entity: Article.entity(), sortDescriptors: [], predicate: predicate)
回答2:
Assuming you have your managedObjectContext set up as such;
@Environment(\.managedObjectContext) var moc
then I believe this solution might work for you.
func deleteArticle(at index: IndexSet) {
for i in index {
// pull the article from the FetchRequest
let article = articleRows[i]
moc.delete(article)
}
// resave to CoreData
try? moc.save()
}
call that method at the end of your ForEach block with;
.onDelete(perform: deleteArticle)
That said I am not familiar with the way you are doing the fetch request so you made need to do some tweaking.
- Dan
来源:https://stackoverflow.com/questions/62636252/swiftui-how-to-update-data-with-fetchrequest-in-init