This is the 7th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

preface

I wrote a long time ago about the shortcomings of Flutter: Enumerations, presumably to poke fun at the weakness of the Dart language level of enumeration, which prevents some of the UI’s state-altering capabilities from working with Flutter.

I’ll leave it at that, but I’ve actually explored and thought about it a little bit in Swift, but I haven’t fully practiced it in RxSwift per se.

Write down some notes here.

The data model returned by network requests is defined through generics

HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse: HttpResponse:

Struct HttpRespone<T: Codable> {/// let code: String? // Let message: String? Let data: T? }Copy the code

Use UI components in protocol and UIKit

I’m trying to write an empty protocol like this and make UIView adhere to it

protocol Widget {}

extension UIView: Widget {}
Copy the code

We all know that Any is also a null protocol, and that all defined types implicitly obey it, so Any can represent Any type.

And we know that basically all OF the UI components are derived by inheriting UIView, making UIView comply with the Widget protocol, so you can think of all the components in UIKit flattening out at once.

Note: We say almost all UI components here because there are some UI components that do not inherit UIView, such as UIBarButtonItem:

open class UIBarButtonItem : UIBarItem, NSCoding {}

open class UIBarItem : NSObject, NSCoding, UIAppearance {}

For UIBarItem, we can try to handle it separately:

extension UIBarItem: Widget {}
Copy the code

Define closures to build pages from data

typealias BuilderWidget<T: Codable> = (HttpRespone<T>) -> Widget
Copy the code

This closure is typically used to build the UI out of data, pointing to widgets as returns, and UIView complies with the Widget protocol.

Defining state enumeration

Enumerated the main body

In general, a page is divided into the following situations:

  • loading

  • error

  • Success:

    • hasContent

    • noData

So our enumeration can be defined as follows:

enum ViewState<T: Codable> {

    case loading

    case error

    case success(ViewSuccess)

    enum ViewSuccess {

        case noData

        case content(BuilderWidget<T>, HttpRespone<T>)

    }

}
Copy the code

Here I use the features of Swift enumeration — the enumeration is parameterized, with ViewSuccess in the SUCCESS state, and the closure and data to build the UI parameterized in viewSuccess.content for ease of call.

Enumerate the extended properties of a classification

In the enumeration category, I want to build different UI components using state values. This is just a preliminary validation case, because the custom Widget protocol is returned, so the compilation does not report an error:

extension ViewState {

    var view: Widget {
        switch self {
        case .error:
            return UIButton()

        case .loading:
            return UIActivityIndicatorView(style: .gray)

        case .success(let successState):
            switch successState {

            case .noData:
                return UILabel()

            case .content(let builderWidget, let response):
                return builderWidget(response)

            }
        }
    }
}
Copy the code

Alternatively, we can extend the data property to specifically get network request values in enumeration state:

extension ViewState {

    var data: T? {

        switch self {
        case .error:
            return nil

        case .loading:
            return nil

        case .success(let successState):
            switch successState {
            case .noData:
                return nil

            case .content(_, let response):
                return response.data
            }
        }
    }
}
Copy the code

Thinking of application direction

  • I consider using MVVM mode to program in THE RxSwift framework. In the ViewModel layer, the obtained network data is converted into a sequence of view states, and then the ViewModel and ViewController have chemical reactions.

  • Consider the idea of building pages with this kind of enumeration in SwiftUI.

SwiftUI

I tried to consider building pages in this form in SwiftUI, of course, it may also be because my SwiftUI is too clumsy and I don’t have a good idea at present:

Import SwiftUI @available(iOS 13.0, *) TypeAlias BuilderView = () -> View @Available (iOS 13.0, *) Extension ViewState: View {/// This some View returns some View /// but it must be of a unique type. For example, if you return EmptyView() in.error, you will immediately get an error. Var body: some View {switch self {case.error: return Text("") case.loading: return Text("") case .success(let successState): switch successState { case .noData: return Text("") case .content(_): return Text("") } } } }Copy the code

Typealias BuilderView = () -> View closure typeAlias BuilderView = () -> View closure

typealias BuilderView = () -> some View
Copy the code

Error reporting directly:

‘some’ types are only implemented for the declared type of properties and subscripts and the return type of functions

Var body: The return type of some View must be the same as that of some Viwe. For example, in the loading state, Text is returned, so in other states, Text is returned.

I consider wrapping an intermediate Container layer here to convert Text to Container(Text) and Button to Container(Button) to ensure that the var body: Type consistency in some View returns is still under consideration. How to define an input parameter constructor to do this, or how to define multiple static functions?

Here is an example and idea:

@available(iOS 13.0, *) struct Container: View {let text: String var body: some View {return text (text)}}Copy the code

Reference documentation

Flutter: The disadvantage of enumeration

conclusion

This article may be a little crossover, or a little unreliable, there are a lot of places to practice and thinking.

Later, I may introduce you to the practice of this idea with Flutter.

If you have any good ideas, welcome to exchange.