< How to save images to the user’s photo library | Importing an image into SwiftUI using UIImagePickerController > |
The first step in our project is to build the basic user interface, which for this app will be:
NavigationView
so we can show our app’s name at the top.Initially the user won’t have selected an image, so we’ll represent that using an @State
optional image property.
First add these two properties to ContentView
:
@State private var image: Image?
@State private var filterIntensity = 0.5
Now modify the contents of its body
property to this:
NavigationView {
VStack {
ZStack {
Rectangle()
.fill(Color.secondary)
// display the image
}
.onTapGesture {
// select an image
}
HStack {
Text("Intensity")
Slider(value: self.$filterIntensity)
}.padding(.vertical)
HStack {
Button("Change Filter") {
// change filter
}
Spacer()
Button("Save") {
// save the picture
}
}
}
.padding([.horizontal, .bottom])
.navigationBarTitle("Instafilter")
}
There are lots of placeholders in there, and we’ll be filling them piece by piece as we work through this project.
For now, I want to focus on this comment: // display the image
. This is where we need to show the selected image if we have one, but otherwise we should show a prompt telling the user to tap that area to trigger image selection.
Now, you might think this is a great place to use if let
and try replacing that comment with something like this:
if let image = image {
image
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
However, if you try building that you’ll see it doesn’t work – you’ll get a fairly obscure error message along the lines of “Closure containing control flow statement cannot be used with function builder ViewBuilder”.
What Swift is trying to say is it has support for only a small amount of logic inside SwiftUI layouts – we can use if someCondition
, but we can’t use if let
, for
, while
, switch
, and so on.
What’s actually happening here is that Swift is able to convert if someCondition
into a special internal view type called ConditionalContent
: it stores the condition and the true and false views, and can check it at runtime. However, if let
creates a constant, and switch
can have any number of cases, so neither can be used.
So, the fix here is to replace if let
with a simple condition, then rely on SwiftUI’s support for optional views:
if image != nil {
image?
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
That code will now compile, and because image
is nil
you should see the “Tap to select a picture” prompt displayed over our gray rectangle.
SPONSORED ViRE offers discoverable way of working with regex. It provides really readable regex experience, code complete & cheat sheet, unit tests, powerful replace system, step-by-step search & replace, regex visual scheme, regex history & playground. ViRE is available on Mac & iPad.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.