One week with SwiftUI

I just wrapped up a week of working with SwiftUI full time. It certainly has some rough edges and each new beta version brings a lot of changes. Here is a recap of what’s working for me and what I still need to figure out.

List views are really simple in SwiftUI. The first layout that loads in my app is a List view has two main sections. The first section has a few rows for some saved queries that I’ll implement later, the second section is dynamic data from Core Data. Xcode Beta 5 introduced some new property wrappers and environment variables for working with Core Data. You can read more about these additions here.

Data entry: I made some simple forms with a few fields and a custom control for picking colors. The only problem I’m having with data entry is actually with the modal presentation implementation of SwiftUI. I call the sheet modifier and pass it a view, but this has some issues with not loading data on repeated calls. I’m calling this modal sheet from the main list view for adding new records, and from a detail view for editing existing records. I have an issue where I can’t get the list view to update when I modify a record that is a few views away (List > Detail > Edit). I think this has something do do with the way that I’m loading the list with Core Data records, as there is nothing that is triggering a refresh when I save the modified record. I need to figure out a better way to setup a publisher with Core Data. A possible workaround for this is to implement record editing on the list rows, just like when a user swipes a table row to disclose an edit button. I just can’t seem to figure out how to do that yet. I may use the new ContextMenu instead if I can’t figure it out soon.

Button("Add List") {
    self.editModal = true
}
.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 20))
.accentColor(Color(Theme.shared.appMainTint))
                          
.sheet(isPresented: $editModal,
       onDismiss: {
        self.timelineEditModal = false
},
       content: {
        ListEditView()
            .environment(\.managedObjectContext, self.managedObjectContext)
})

Color Picker: The list based item in my app is composed of of a name, color, and icon. I wanted to try to mimic the new color picker in the new version of the Reminders app. While SwiftUI doesn’t have an alternative to the Collection View yet, I was able to get my color picker working by dynamically calculating a number of columns. I used Geometry Reader to get the width of the parent view, then just divided it by the size (including padding) that I wanted each color to take up. I passed that number to a child view that parses out a list of colors into rows and columns. I got the idea for the grid here. I’m planning on implementing something similar with the icon, using a subset of SF Symbols.

Dynamically sized color picker on iPad and iPhone.

I spent a large part of today refactoring a lot of my code into smaller views that are easier to reason about. Xcode can have a hard time handling complex views with lots of embedded views, so it can be helpful to break them into small components where possible.

Some issues I haven’t figured out:

  1. Master Detail by default – On iPad I get free Master Detail by default, but I’m not certain this is right for my app. I have not found a way to just fill the screen with my list view. There is also an annoying issue that iOS loads an empty detail view when in portrait mode. I can’t believe this is still the default behavior after years of iOS but it is… 
  2. Modal views seem to break when loaded from a List item. They will work correctly the first time, but when opened two or more times they do not load the data that is being passed to them. I was able to confirm that the data is being passed, but SwiftUI is not using it to update the views.
  3. iOS 13 has a new (old) style for rounding the corners of grouped tables/lists. I can’t find a way to do this yet. .listStyle(GroupedListStyle()) does not do the trick.
  4. List Edit Mode – I can toggle edit mode on, but have yet to figure out what to do next. I want to let users reorder rows, and I want to show an info button that will open a modal sheet for modifying a record.

SwiftUI is still new and can be frustrating at times but I think I can safely say that I’m going to make the production version of my app with it. In one week of work I caught up to the UIKit version of my app, which took nearly two months. Granted, a lot of that time was focused on planning and design, which benefited both versions. I think I’ll stick with SwiftUI just so I never have to deal with Auto Layout ever again.