Content Modeling in Apple
Learn how to handle different content-type and nestable blocks, render rich text, and use story references to manage content globally.
In the existing space, create the following blocks:
- An
articlecontent type block with the following fields:title: Textcontent: Rich text
- A
featured-articlesnestable block with the following field:articles: References
Next, create an Articles folder, open it, and create a few stories that use the article content type.
Finally, add the featured-articles block to the body field of the Home story, and select the created articles to feature.
Create and register blocks
Section titled “Create and register blocks”Update the BlockLibrary.swift file to add cases for the new blocks.
import StoryblokClient
@BlockLibraryenum Block: Decodable, Hashable { case feature(name: String) case grid(columns: [Block]) case page(body: [Block]) case teaser(headline: String) case article(Article) case featuredArticles(articles: [Story<Article>]) case unknown
enum CodingKeys: String, CodingKey { case featuredArticles = "featured-articles" }
nonisolated struct Article: Decodable, Hashable { let title: String let content: RichText<Block> }}The fields of the article and featured-articles blocks are defined as follows:
Article.contentis defined asRichText<Block>which can represent any rich text node (a document in this case).featuredArticles.articlesis defined as[Story<Article>]which will cause the referenced stories to be resolved and returned. To receive only the UUIDs of the linked stories change the type of the field to[UUID].- The special nested enumeration
CodingKeysis declared to map the block’s technical name,featured-articles, which is not a valid Swift identifier, to thefeaturedArticlescase. - Instead of labeled associated values for the individual fields of the block, the added
articlecase declares the nestedArticlestruct as a single unnamed associated value. This allows the sharing of theArticletype with thefeaturedArticlescase.
Next, add views for these blocks to the View conformance in BlockView.swift.
import SwiftUIimport StoryblokClientimport RichTextView…extension Block: View { var body: some View { switch self { case let .page(body): LazyVStack(alignment: .leading, spacing: 0) { ForEach(body, id: \.self) { $0 } } … case let .featuredArticles(articles): VStack(alignment: .leading, spacing: 8) { Text("Featured Articles") .font(.title2) ForEach(articles, id: \.self) { article in NavigationLink(article.content.title, value: article) } } .padding() case let .article(article): article // Article conforms to View (below) case .unknown: Text("Unknown block type") } }}
extension Block.Article: View { var body: some View { VStack(alignment: .leading, spacing: 16) { Text(title) .font(.largeTitle) content } .padding() }}Views for featuredArticles and article are added alongside the existing blocks:
- The
featuredArticlesview renders links to the featured articles, each aNavigationLinkcarrying the articleStoryinstance for immediate display of the selected article. - The
articlecase returns theArticlestruct itself, whoseViewconformance is added in the extension below which places its rich textcontentdirectly in the view hierarchy, where it is rendered by theRichTextViewlibrary.
Finally, update ExampleApp.swift to add a navigation destination for article stories, and the onStoryLink modifier to handle any story links present in the rich text content.
import SwiftUIimport StoryblokClientimport RichTextViewinternal import URLSessionExtension… .navigationDestination(for: Story<Block>.self) { story in StoryView(client.story(story.uuid), story: story) } .navigationDestination(for: Story<Block.Article>.self) { story in StoryView(client.story(story.uuid), story: story) } } .onStoryLink { uuid, _ in path.append(uuid) } }…Run the app and see the home story with the links to the featured articles rendered. Tapping any link navigates to the article.
Related resources
Section titled “Related resources”Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community