Swift Table View with Calendar Section Headers
Scenario
Our app contains book records in a Core Data database. We defined one of the Book attributes as Published Date. We wish to present a table view, sectioned by Publication Year, where each section contains the books published in that specific year.
Technique
We need to use the Swift DateFormatter() and the Calendar function of the Publication Date attribute to extract the Year component. Then we need to exclude any nil Publication Date values and sort the valid records by Publication Date. When building the table view sections, we shall extract the Year component and use it as the section header for books of the same publication year.
App Model
We based the article on the AppsGym Books model app, which is published on Apple’s App Store (as 8Books). You can review the Query result of ‘Books by Publication Year’ in the app. You can also download the complete Xcode project on AppsGym.com for free.
User Interface
The model app Queries menu shows options to list of book by different user-selected criteria (author, genre, publication year, etc.). The query result table view utilises dynamic section headers (year component of Publication Date) to group related records in a mini section, by publication year, within the overall list of books.
The file BooksByPubYearTableViewController.swift
controls the layout, order, and navigation of the UITableViewController to show books by publication year. The app model sample data has multiple book publication dates in different years; the user can add their own books after removing the sample data as needed. The logic adds the appropriate Publication Year section header dynamically, after sorting the books by the book Publication Date.
The Queries.storyboard
contains the storyboard for the Pub Year query.
Logic
- Declare the variable arrays that will contain the valid Query Books to allow section headers:
queryBooks: [Book], contains all fetched Core Data records
sectionHeaderTitles: [String], contains texts of all Publication Years
sectionBooks: [Book], contains books by sections
sectionBooksArrays [[Book]], contains arrays where each array is one section books
2. Retieve all the books from Core Data and populate queryBooks[]
3. Filter and sort quearyBooks[] by Publication Date
4. Loop through the queryBooks[] array and compare each book publication year (a calendar.component of the Publication Date) with the prior book year of publication (include special logic to the 1st time through the loop, so assume the year to be 1900 or similar)
5. Add the book to the sectionBooks[] array, the publication year to the sectionHeaderTitles[] and the similar publication year books to the sectionBooksArrays.
6. Show the table view, using the special section header functions:
heightForHeaderInSection(..) and viewForHeaderInSection(..)
Code
The Swift code snippets below are extracts from BooksByPublicationYearTableViewController.swift
viewDidLoad()
viewWillAppear()
SECTION HEADERS
cellForRowAt()
BooksByPublicatinYearTableViewController.swift didSelectRow() will navigate to the selected row Book Details view BookDetailsViewController.swift
We establish the connection between the ByPublicatinYear query and the Book Details by assigning a reference to the Book Details navigation controller, in Custom Class attribute Identity: Storyboard ID, and linking to the reference from the query Storyboard Reference ID.
didSelectRowAt() and prepare(for segue:)
UTILITIES
The article covered the complete logic and code to present a table view sectioned by a calendar function, in our example the Year of a Publication Date attribute on the Book record. Hope you find it useful. Thanks for reading!