kviskring
kviskring

Reputation: 35

One object in multiple sections when sorting with NSFetchedResultsController

I’ve just started using Core Data and NSFetchedResultsController and I'm kind of stuck. I've a Book entity which has a category attribute of type String. The data is loaded into a collection view and grouped by sections based on this category. All’s working fine this way, but the problem is that a Book should be able to appear in multiple categories (and collection view sections). I could change the category’s type to an Array of String, but how would I do the sorting then?

let request = Book.fetchedRequest() as NSFetchRequest<Book>
let categorySort = NSSortDescriptor(key: #keyPath(Book.category)), ascending:true)
request.sortDescriptors = [categorySort]

do {
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: #keyPath(Book.category)), cacheName: nil) 
try fetchedResultsController.performFetch()
} catch let error as NSError {
print(“Could not fetch. \(error), \(error.userInfo)”)
}

Should I just give up on using NSFetchedResultsController or is it possible to make this work?

Upvotes: 3

Views: 192

Answers (2)

Martin R
Martin R

Reputation: 539745

... a Book should be able to appear in multiple categories (and collection view sections).

Should I just give up on using NSFetchedResultsController or is it possible to make this work?

What you describe cannot be achieved with a fetched results controller. NSFetchedResultsController takes all fetched objects (which are possibly filtered by a predicate), sorts them according to the sort descriptors, and groups them according to the sectionNameKeyPath argument.

There is no way that a fetched results controller provides the same object multiple times (in the same or in different sections).

Upvotes: 3

Skywalker
Skywalker

Reputation: 1586

I don't think there is any problem in keeping the category attribute as a string. Just change the way you approach the array of Books.

Make an array of categories like

var booksInCategories: [[Book]] = []

This variable will hold all the books in one category inside each array. Let's assume your array of books are called books.

var books: [Book] = []

Then put each book in each of the categories and add it to the booksInCatogories object. Lets assume you have all the categories as another array of strings.

var categories = ["Fiction", "Science", "Children", "Education"] // just an example

If there are n categories, then there would be n arrays of books in booksInCatogories.

for category in categories {
    var booksInCategory: [Book] = []
    for book in books {
        if book.category.range(of: category) != nil { // checks if category string contains particular category
            booksInCategory.append(book)
        }
    }
    if booksInCategory.count > 0 { // to exclude empty array if a category doesn't have any books under it
        booksInCategories.append(booksInCategory)
    }
}

You can now use booksInCategories array to display all the books which belong to each category under each section using each array in booksInCategories.

Upvotes: 0

Related Questions