Buried in the iOS 14.5 beta 3 release notes is this little update:

You can now apply multiple sheet(isPresented:onDismiss:content:) and fullScreenCover(item:onDismiss:content:) modifiers in the same view hierarchy. (74246633)

What does this mean in practice? As a comparison, here’s a simple View and its accompanying model.

In this iOS 14.4 example:

  1. there’s only one .sheet modifier
  2. the modifier has a switch statement on an enum of potential sheets to display
  3. the model has an additional property of displaySheet to control when sheets are displayed
struct ContentView: View {

	@StateObject private var model = ContentViewModel()
	
	var body: some View {
		VStack(spacing: 10) {
			Button(action: {
				model.sheetToDisplay = .green
			}, label: {
				Text("Show Sheet 0")
			})
			
			Button(action: {
				model.sheetToDisplay = .red
			}, label: {
				Text("Show Sheet 1")
			})
			
			Button(action: {
				model.sheetToDisplay = .blue
			}, label: {
				Text("Show Sheet 2")
			})
		}
		.sheet(isPresented: $model.displaySheet, content: { //1
			switch model.sheetToDisplay { // 2
			case .green:
				Color.green
			case .red:
				Color.red
			case .blue:
				Color.blue
			case .none:
				EmptyView()
			}
		})
		
	}

}

class ContentViewModel: ObservableObject {

	enum SheetToDisplay {
		case green, red, blue, none
	}
	
	@Published var displaySheet: Bool = false // 3
	@Published var sheetToDisplay: SheetToDisplay = .none {
		didSet {
			sheetToDisplay != .none ? (displaySheet = true) : (displaySheet = false)
		}
	}

}

Now, however, things have been simplified. In this updated version for iOS 14.5:

  1. There are multiple .sheet modifiers
  2. Each sheet has its own isPresented property in the model
struct ContentView: View {

	@StateObject private var model = ContentViewModel()
	
	var body: some View {
		VStack(spacing: 10) {
	
			Button(action: {
				model.showGreen = true
			}, label: {
				Text("Show Green")
			})
	
			Button(action: {
				model.showRed = true
			}, label: {
				Text("Show Red")
			})
	
			Button(action: {
				model.showBlue = true
			}, label: {
				Text("Show Blue")
			})
	
		}
		.sheet(isPresented: $model.showGreen, content: { // 1
			Color.green
		})
		.sheet(isPresented: $model.showRed, content: { // 1
			Color.red
		}) 
		.sheet(isPresented: $model.showBlue, content: { // 1
			Color.blue
		})
	}
}

class ContentViewModel: ObservableObject {

	@Published var showGreen: Bool = false // 2
	@Published var showRed: Bool = false // 2
	@Published var showBlue: Bool = false  // 2

}

With multiple sheets being permitted, and each sheet having its own isPresented binding in the model, I find the code to be that little bit more logical.1


  1. If you try the updated code on <= iOS 14.4, only the blue sheet will display. ↩︎