NEW: Join my free 100 Days of SwiftUI challenge today! >>

Building a list with @FetchRequest

Paul Hudson    @twostraws   

Right now our ContentView has a fetch request property like this:

@FetchRequest(entity: Book.entity(), sortDescriptors: []) var books: FetchedResults<Book>

And we’re using it in body with this simple text view:

Text("Count: \(books.count)")

To bring this screen to life, we’re going to replace that text view with a List showing all the books that have been added, along with their rating and author.

We could just use the same star rating view here that we made earlier, but it’s much more fun to try something else. Whereas the RatingView control can be used in any kind of project, we can make a new EmojiRatingView that displays a rating specific to this project. All it will do is show one of five different emoji depending on the rating, and it’s a great example of how straightforward view composition is in SwiftUI – it’s so easy to just pull out a small part of your views in this way.

So, make a new SwiftUI view called “EmojiRatingView”, and give it the following code:

struct EmojiRatingView: View {
    let rating: Int16

    var body: some View {
        switch rating {
        case 1:
            return Text("1")
        case 2:
            return Text("2")
        case 3:
            return Text("3")
        case 4:
            return Text("4")
        default:
            return Text("5")
        }
    }
}

struct EmojiRatingView_Previews: PreviewProvider {
    static var previews: some View {
        EmojiRatingView(rating: 3)
    }
}

Tip: I used numbers in my text because emoji can cause havoc with e-readers, but you should replace those with whatever emoji you think represent the various ratings.

Notice how that specifically uses Int16, which makes interfacing with Core Data easier. And that’s the entire view done – it really is that simple.

Now we can return to ContentView and do a first pass of its UI. This will replace the existing text view with a list and a ForEach over books. For the ForEach identifier we can actually use \.self so that it uses the whole object as the identifier, but things are trickier when it comes to creating views inside the ForEach.

You see, all the properties of our Core Data entity are optional, which means we need to make heavy use of nil coalescing in order to make our code work. We’ll look at an alternative to this soon, but for now we’ll just be scattering ?? around.

Inside the list we’re going to have a NavigationLink that will eventually point to a detail view, and inside that we’ll have our new EmojiRatingView, plus the book’s title and author. So, replace the existing text view with this:

List {
    ForEach(books, id: \.self) { book in
        NavigationLink(destination: Text(book.title ?? "Unknown Title")) {
            EmojiRatingView(rating: book.rating)
                .font(.largeTitle)

            VStack(alignment: .leading) {
                Text(book.title ?? "Unknown Title")
                    .font(.headline)
                Text(book.author ?? "Unknown Author")
                    .foregroundColor(.secondary)
            }
        }
    }
}

We’ll come back to this screen soon enough, but first let’s build the detail view…

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5