the most successful UI framework in the history of software. • Incredibly versatile, scaling from the iPhone to the Mac. • Is the backbone of iOS and will be for many years to come.
if {} else if {} else {} branch in the view's body will sure become more and more complex as we add features to this view. • Cyclomatic Complexity will spiral out of control • Could be improved with an enum but the core issue remains. • Previews will hit the actual network. • These should be treated as Unit Tests: should work regardless of the network status.
the way we architecture SwiftUI apps was that we could add two initializers to our DataModel objects: • An async initalizer for when the view is run regularly. • A sync initializer when the view is Previewed
can remove those pesky properties: • var isLoading: Bool • var error: Error? • We are instead using the Swift way: async throws. • SwiftUI Previews work now by using the sync initialiser. • If Previews don ’ t work, it ’ s not SwiftUI!
when there is actual data to show. • It made no semantical sense for it to be holding an empty array • Reduced complexity • For example, any error that occurs after BookList is on screen is handled (marking a book as read for example) is handled in a different context
tightly coupled to BookList and it ’ s DataModel. • Options to make it reusable are: • Use Swift Macros to auto-generate the code • Use Swift Generics to inject the View.
some View { AsyncView( id: "book-list", dataGenerator: { try await DataModel(urlSession: urlSession) }, hostedViewGenerator: { BookList(dataModel: $0) }, errorViewGenerator: { error, onRetry in ErrorView(error: error) }, loadingViewGenerator: { ProgressView() }) } } dataGenerator: The function that generates the data that is required for your HostedView
that de fi nes types that return placeholder data to be used for Previews or loading states. public protocol PlaceholderDataProvider { associatedtype Data static func generatePlaceholderData() -> Data }
that de fi nes types that return placeholder data to be used for Previews or loading states. public protocol PlaceholderDataProvider { associatedtype Data static func generatePlaceholderData() -> Data } extension BookList: PlaceholderDataProvider { static func generatePlaceholderData() -> DataModel { .init(books: [Book(…), Book(…), …]) } }
developer • @EnvironmentObject is fine • Interoperability with UIKit is done via UIHostingController. • Rewrites of specific screens have drastically reduced the codebase size. • You can always “drop down” to UIKit if SwiftUI doesn ’ t provide what you need.