Notes to myself about SwiftUI - 1🐦

I've been studying Stoicism, and one of the important books on this topic is 'Meditations' by Marcus Aurelius, who was a wise emperor and philosopher. In his book, he wrote notes to himself, creating a valuable guide to Stoicism. He talks to himself in these notes. Now, in this article, I'll be writing notes to myself, while focusing on using SwiftUI.

UI development

  • ContentView is the root view in the hierarchy.

  • There can be a maximum of 10 views inside a VStack.

  • The default layout priority is 0. The higher the number, the higher the priority to have enough space to not be truncated.

  • You can add layers on top (.overlay()), behind (.background())

  • All the modifiers (such as padding, background...) create new layers in the view tree, their sequence often matters. Calling .padding().background(..) is different than calling .background(..).padding().

  • In view builders, you can only write a very limited subset of Swift. For example, you cannot write loops, guards, or if let's. However, you can write simple Bool if statements.

  • When we are talking about views, we are talking about values conforming to the View protocol.

  • Calling APIs like .frame and .offset does not modify the properties of the view but rather wraps the view in a modifier.

  • Stop using UIScreen.main.bounds. Be open to using GeometryReader. GeometryReader is a container view to inspect and use properties that can help with positioning other views within it. We can access properties like height, width and safe area insets.

  • If we would like to update what's onscreen, we can't update it directly. Instead, we have to modify properties that marked with the following attributes @State, @ObservedObject or @EnvironmentObject and let SwiftUI figure out how the view tree has changed.

  • Changing state properties is the only way to trigger a view update in SwiftUI.

  • SwiftUI views are values, not objects. They are immutable, transient descriptions of what should be onscreen.

  • A binding is essentially a getter and a setter for a captured variable. SwiftUI's property wrappers have a corresponding binding that you can access by using the $ prefix.

  • In property wrapper terminology, the binding is called a projected value.

  • All the property wrappers SwiftUI uses for triggering view updates conform to the DynamicProperty protocol.

  • VStack loads all child views when displayed. When we use LazyVStack, SwiftUI will not load them unless it needs to show them on the screen. Using LazyVStack increases performance. We are also able to pin a section header and footer. (VStack doesn't allow this.)

  • AnyView can contain completely arbitrary view trees with no requirement that their type be statically fixed at compile time. While this gives us a lot of freedom, AnyView should be something we only use as a last resort. This is because using AnyView takes away essential static-type information about the view tree that otherwise helps SwiftUI perform efficient updates.

  • We can best make use of SwiftUI’s smart view tree updates when we place state properties as locally as possible. Conversely, it’s the worst possible option to represent all model states with one state property on the root view and pass all data down the view tree in the form of simple parameters, as this will cause many more views to be needlessly reconstructed.

  • The State type also enables dependency tracking. When a view’s body accesses the wrappedValue of a State variable, a dependency is added between that view and the State variable. This means SwiftUI knows which views to update when the wrappedValue changes.

Testing

  • You can add different devices to previews to see various devices by writing .previewDevice("iPad Pro (9.7 inch)")

  • You can add different orientations to previews by writing

    .previewInterfaceOrientation(.landscapeLeft)

  • The List component uses UITableView in iOS 15, and UICollectionView in iOS 16. If you are using List, there might be bugs about this difference.

  • Make sure you test on different iOS versions because most probably there will be unexpected bugs.

  • Testing on a physical device is always worth it.

Programming mentality in general

  • If you see something new and don't understand why it's used in your codebase, research about it.

Some notes are based on my experiences, some of them are taken from Thinking in SwiftUI book and SwiftUI Views Mastery book. Hope you enjoyed this article, looking forward to publish part 2. Happy coding!