Working with Lists in Multiplatform SwiftUI Apps

One of SwiftUI’s best features is you can use it to make apps that run on both iOS and Mac. Almost every SwiftUI article you find online is about iOS development, but most of the material also applies to Mac as well.

Lists are one area of SwiftUI where there are large differences between iOS and Mac. If you read an article about lists and try to use the code in a Mac app, you’ll run into problems. This article provides guidance on writing list code that works in both iOS and Mac apps.

Differences in List Behavior

The main reason you can’t use the same list code on iOS and Mac is because the way people interact with lists is different in iOS and Mac.

iOS apps have an Edit button that people use to delete and move items. When someone wants to delete a list item, they tap the Edit button. Each item has a Delete button next to it. Tapping the button deletes the item. Because each list item has a Delete button, you don’t have to keep track of the selected items.

Mac apps don’t have an Edit button for deleting and moving list items. In a Mac app, people delete list items by selecting them and either pressing the Delete key or clicking a Delete button. People move items by selecting them and dragging them to the desired destination. When developing a Mac app that uses lists, you must keep track of the selected item.

Tip: Create Separate List Views for iOS and Mac App Targets

Because list behavior is so different between iOS and Mac apps, you should create separate SwiftUI list views for the iOS and Mac versions of your app. If you try to support iOS and Mac in the same view, your code is going to be littered with #if os() checks, making the code tough to read.

You can share a list view if the list only displays data. If your app doesn’t allow people to delete and move items, it doesn’t require an Edit button on iOS. In that case you can share the view.

Deleting List Items

iOS

Deleting a list item on iOS requires the following steps:

  • Place the list items in a ForEach block.
  • Add an .onDelete modifier to the ForEach block.
  • Write a function to delete the item from its array.

You can’t apply the .onDelete modifier directly to a list on iOS. That’s why you must place the list items in a ForEach block.

Call the function to delete the item in .onDelete.

.onDelete(perform: deleteItem)

The function to delete the item takes an IndexSet as an argument. Call the array’s remove function to remove the item from the array.

func deleteItem(at offsets: IndexSet) {
  array.remove(atOffsets: offsets)
}

Mac

Deleting a list item on Mac requires the following steps:

  • Keep track of the selected item.
  • Add an .onDeleteCommand modifier to the list.
  • Write a function to delete the item from its array.

The usual way to keep track of the selected list item is to add a @State property to the view.

@State private var selection: Model? = nil

Call the function to delete the item in .onDeleteCommand.

.onDeleteCommand {
  deleteItem()
}

Removing an item from an array in a Mac app is trickier. Call the array’s firstIndex function to find the selected item in the array. If the item is in the array, call the remove function to delete the item.

func deleteItem() {
  if let selection = self.selection,
    let selectionIndex = array.firstIndex(of: selection) {
                
    array.remove(at: selectionIndex)
  }
}

Moving List Items

iOS

Moving list items on iOS requires the following steps:

  • Place the list items in a ForEach block.
  • Add an .onMove modifier to the ForEach block.
  • Add a function to move the item in its array.

You can’t apply the .onMove modifier directly to a list on iOS. That’s why you must place the list items in a ForEach block.

Call the move function in .onMove

.onMove(perform: move)

The move function takes two arguments: a location for the source and a location for the destination. Call the array’s move function to move the items in the array.

func move(from source: IndexSet, to destination: Int) {
  array.move(fromOffsets: source, toOffset: destination) 
}

Mac

Moving list items on Mac requires the following steps:

  • Add an .onMove modifier to the list.
  • Add a function to move the item in its array.

You have to do a little more work on Mac with the .onMove modifier, providing the arguments in the closure to call the move function.

.onMove { indices, destination in
  move(from: indices, to: destination)
}

The move function is the same as iOS.

func move(from source: IndexSet, to destination: Int) {
  array.move(fromOffsets: source, toOffset: destination)
}

Want More Articles Like This?

This article is an example of the exclusive articles for Swift Dev Journal newsletter subscribers. Subscribers also get a guide on going from tutorials to making your first app, discounts on books, and any benefits I decide to add later.

Use the form at the end of this article to subscribe to the newsletter.

Get the Swift Dev Journal Newsletter

Subscribe and get exclusive articles, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

    We won't send you spam. Unsubscribe at any time.