Printed on: July 10, 2024
Xcode 16 and iOS 18 include a function that permits us to construct elaborate preview environments utilizing a brand new PreviewModifier
protocol. This protocol permits us to outline objects that may create a single context or surroundings that’s cached and used throughout your SwiftUI previews.
That is helpful as a result of it implies that you can, for instance, populate a database with a bunch of mock knowledge that’s then utilized in your previews.
You can too use PreviewModifier
to use particular styling to your previews, to wrap all of them in a particular wrapper, and extra.
Primarily, they’re a device that lets you configure your previews persistently throughout the board.
Adorning views utilizing PreviewModifier
The PreviewModifier
protocol specifies two strategies you could implement:
- A static
makeSharedContext
methodology - An occasion methodology known as
physique
The physique
occasion strategies is handed the view that’s being previewed and a Context
. This context can both be an object that you just created in makeSharedContext
or Void
if you happen to don’t implement makeSharedContext
.
For this instance, let’s assume that you just went forward and didn’t implement makeSharedContext
. In a scenario like that, we are able to use PreviewModifier
to embellish a view for our previews. For instance, we may wrap it in one other view or apply some styling to it.
I’m fairly positive that you just’re extra inventive than me so I’m simply going to go forward and present you ways you’d apply a orange background to your previewed view. Yeah, I do know… very inventive. The purpose is to point out you ways to do that so as to do one thing a lot smarter than what I’m describing right here.
struct OrangeBackground: PreviewModifier {
func physique(content material: Content material, context: Void) -> some View {
content material
.padding()
.background {
RoundedRectangle(cornerRadius: 16)
.fill(.orange)
}
}
}
#Preview(traits: .modifier(OrangeBackground())) {
Textual content("Whats up, world!")
}
Let’s take a look at the PreviewModifier
first, after which I’ll clarify how I utilized it to my preview.
The modifier is outlined as a struct
and I solely carried out the physique
operate.
This operate is padded Content material
which is no matter view the #Preview
macro is getting used on (on this case, Textual content
), and it receives a context. On this case Void
as a result of I didn’t make a context.
The content material
argument could be styled, modified, and wrapped nevertheless you want. It’s a view so you are able to do issues like give it a background, remodel it, modify its surroundings, and far far more. Something you are able to do with a view within a View
physique you are able to do right here.
The principle distinction is that you just’re receiving a completely instantiated occasion of your view. Which means you may’t inject new state or bindings into it or in any other case modify it. You possibly can solely apply view modifiers to it.
This brings us to our subsequent function of PreviewModifier
making a context to supply mocked knowledge and extra.
Utilizing PreviewModifier to inject mock knowledge
To inject mock knowledge into your previews via PreviewModifier
all it is advisable to do is implement the makeSharedContext
methodology from the PreviewModifier
protocol. This methodology is static
and known as as soon as for all of your previews. Because of this the context that you just create on this methodology is reused for all your previews.
In observe that is good as a result of it means you get constant mock knowledge to your previews with out the overhead of recreating this knowledge steadily.
Right here’s what a pattern implementation for makeSharedContext
seems to be like:
struct MockDataSource {
// ...
}
struct OrangeBackground: PreviewModifier {
static func makeSharedContext() async throws -> MockDataSource {
return MockDataSource()
}
}
On this case, I’m creating an occasion of some knowledge supply in my makeSharedContext
methodology. This MockDataSource
would maintain all mocks and all knowledge for my views which is nice.
Nevertheless, the one method for us to actually use that mock knowledge in our view is by including our knowledge supply (or the mocked knowledge) to our previewed view’s surroundings.
struct OrangeBackground: PreviewModifier {
static func makeSharedContext() async throws -> MockDataSource {
return MockDataSource()
}
func physique(content material: Content material, context: MockDataSource) -> some View {
content material
.surroundings(.dataSource, context)
}
}
Since we are able to’t make a brand new occasion of our content material, we are able to’t inject our mock knowledge supply straight into the view via its initializer. The one method we are able to get the info supply to the view is by including it to the surroundings.
This isn’t perfect for my part, however the design is sensible.
I’m additionally fairly positive that Apple designed this API with mocking SwiftData
databases in thoughts and it might work nice for that.
On high of getting to make use of the surroundings, the PreviewModifier
solely works in initiatives that concentrate on iOS 18 or later. Not an enormous downside however it might have been good if utilizing Xcode 16 was ok for us to have the ability to use this useful new API.