Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Francesco Leoni
Francesco Leoni

Posted on

     

Combine CoreData and SwiftUI

Recently I had to build an app usingSwiftUI andCoreData.
I thought CoreData was used almost as you would use it with UIKit, but apparently there are some differences.
This guide is intended as a summary of my experience using CoreData combined with SwiftUI. If I will find other aspects, I will add them to this guide.
So, without further ado, let's begin.

Set-up

This is a pretty straightforward part.

  • If you start a new project you can check the 'Use Core Data' option and 'Host in CloudKit' if you want to save your users data to the cloud. In this case XCode will take care of setting up the project for you. (For the CloudKit part will need to do some extra steps).
  • If you have already a project you'll need to create aPersistence.swift file and a swift file where you initialise the CoreData stack. (You can even create a new project following the previous step, and copy thePersistence.swift file generated by XCode to your project.

Setup the@main app

Now that you have your project, to be able to use CoreData within yourViews, you need to pass themanagedObjectContext down you view hierarchy.
Usually this is done in yourApp.swift file.

@mainstructExampleApp:App{letpersistenceController=PersistenceController.sharedvarbody:someScene{WindowGroup{ContentView().environmentObject(persistenceController).environment(\\.managedObjectContext,persistenceController.container.viewContext)}}}
Enter fullscreen modeExit fullscreen mode

Personally I pass, as an.environmentObject, thePersistenceController itself. Because I like to keep all the CRUD logic inside that struct, but that's up to you. If you want to do so you need to make yourPersistenceController struct conform toObservableObject.
Great, now you're able to create, read, update and deleteNSManagedObjects in yourViews.

TIP:PersistenceController (here is an exemple) is the struct that XCode generates automatically for you when you start a new project with the 'Use Core Data' option checked.

Operating with CoreData

To operate with CoreData in yourView you need to access theNSManagedObjectContext. To do so, you have two options:

  • Using the@Environment wrapper in yourViews
@Environment(\\.managedObjectContext)privatevarviewContext
Enter fullscreen modeExit fullscreen mode
  • Using the@EnvironmentObject wrapper to get your controller, and from it you can access theviewContext or CRUD methods
@EnvironmentObjectprivatevarpersistenceController:PersistenceController
Enter fullscreen modeExit fullscreen mode

Saving the context

You can save the context using the.save() method ofNSManagedObjectContext. Before saving the context you can check whether there are some changes, and save it only if they are present.

do{ifcontainer.viewContext.hasChanges{trycontainer.viewContext.save()}}catch{print(error)}
Enter fullscreen modeExit fullscreen mode

Saving objects

To save aNSManagedObject you first need to instanciate it and than configure its properties. And then save the context.

letnote=Note(context:container.viewContext)note.id=idnote.text=textnote.folder=foldernote.creationDate=Date()saveContext()
Enter fullscreen modeExit fullscreen mode

TIP: You can animate this insertion wrapping this code inside thewithAnimation function of SwiftUI.

Fetching objects

Now the fetching part, this is where I found the most difficulties. Let's start right away.
To fetch objects in SwiftUI the most convenient way of doing it is using the@FetchRequest or@SectionedFetchRequest wrappers, in every singleView you need to read from CoreData.

WARNING: Passing fetched objects betweenViews will break the automatic updates in case you add, edit or delete objects. (If you know a way to pass fetch objects without breaking the updates let me know and I will update this guide)

So you need to add a@FetchRequest in everyView you need CoreData objects and automatic updates. I know it is a bit annoying but it will be worth it.
So, with that said the code is the following:

@FetchRequest(entity:Object.entity(),sortDescriptors:[NSSortDescriptor],predicate:NSPredicate,animation:.default)varobjects:FetchedResults<Object>
Enter fullscreen modeExit fullscreen mode

Or, if you want your objects grouped by a property:

@SectionedFetchRequest(entity:Object.entity(),sectionIdentifier:\\Object.property,sortDescriptors:[NSSortDescriptor],predicate:NSPredicate,animation:.default)varsections:SectionedFetchResults<YourSectionType,Object>
Enter fullscreen modeExit fullscreen mode

To use these sections you just pass them to aList orForEach, and then to anotherForEach.

List(sections){sectioninSection(section.id){ForEach(section){objectin// Configure your view with the object}}}
Enter fullscreen modeExit fullscreen mode

TIP: If you use@SectionedFetchRequest with sorting you may need to specify two sort descriptor. The first will sort the sections and the second one will take care of the objects inside each section. This feature is really useful and requires very little effort.

Using@FetchRequest or@SectionedFetchRequest wherever you add, update or delete an object, the views are automatically updated.
Now, if you need to use a@FetchRequest with aNSPredicate that has a parameter passed from the parentView, I found that the next option works wonderfully.

@FetchRequestvarobjects:FetchedResults<Object>init(id:ID){_objects=FetchRequest<Object>(predicate:NSPredicate(format:"id == %@",id))}
Enter fullscreen modeExit fullscreen mode

This way you can pass your parameter in theinit and use it to filter your results while keeping the automatic updates. The same goes for@SectionedFetchRequest.

Updating objects

To update aNSManagedObject you will need to have theNSManagedObject to update, fetched as described before and update its properties. And then save the context.

note.text=newTextnote.folder=newFoldersaveContext()
Enter fullscreen modeExit fullscreen mode

Deleting objects

To delete aNSManagedObject you will need to have theNSManagedObject to update, fetched as described before and delete it.

viewContext.delete(object)
Enter fullscreen modeExit fullscreen mode

I didn't explained every single CRUD method of CoreData like batch insertion and deletion since this guide is focused on the interaction between CoreData and SwiftUI. EveryNSManagedObjectContext method, background context, performAndAwait, … behaves exactly like it does with UIKit.


Conclusion

That's all I have discovered so far aboutCoreData used withSwiftUI. This guide will be constantly updated.
If you want to suggest a better way of doing something,leave a comment and I will update this guide with the best option.
I hope I helped you with you journey with SwiftUI and iOS development.
See you in the next guide!


If you would like to support my work and see this guide in action check outBrainDump - Notes & Writing
Thank you 🙏


SwiftyLion

This article was originally published onSwiftyLion. Head over there if you like this post and want to read others like it.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Hi! My name is Francesco.I am an iOS / macOS developer and Apple addicted.
  • Joined

More fromFrancesco Leoni

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp