Best-practices to download data from server in SwiftUI

后端 未结 3 1735
失恋的感觉
失恋的感觉 2021-02-10 16:12

My question is a conceptual question.

I have the following code:

struct CategoriesList : View {

    @State pri         


        
相关标签:
3条回答
  • 2021-02-10 16:28

    iOS developers don't seem to be as familiar to this idea as Mac OS developers, in Mac apps we split the controller layer into ViewController and ModelControllers, ViewControllers are responsible for synchronise between the views and the model, ModelControllers are responsible for managing archiving of the model etc, so SwiftUI does away with ViewControllers, but if you have network handling then thats where ModelControllers would be useful, they could handle the synchronising between you remote source and you model, this is how I am currently doing it in a sample application I am working, though I have been wondering if Combine could be used to replace that as well, that will be my next thing to experiment with.

    0 讨论(0)
  • 2021-02-10 16:49

    You could take a look at my answer here.

    Basically you create a model object conforming to BindableObject :

    class LoginModel : BindableObject {
    
        var didChange = PassthroughSubject<LoginModel, Never>()
    
        private(set) var username: String? {
            didSet {
                didChange.send(self)
            }
        }
    
        func load() {
            DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
                self.username = "Sorin"
            }
        }
    }
    

    This example simulates an async server call by using the plain ol' asyncAfter.

    Then, the View links with it and it's automatically updated when the model changes.

    public struct LoginScreen: View {
    
        @ObjectBinding var loginObject = LoginModel()
    
        public var body: some View {
            Group {
                if login.username == nil {
                    Text("Trying to login, please wait...")
                } else {
                    Text("Successful login, the username is \(loginObject.username!)")
                }
            }.onAppear {
                self.loginObject.load()
            }
        }
    }
    

    The key here is to avoid trying to make the View perform anything related to the Model, except displaying it. SwiftUI will resist you all the way :-)

    0 讨论(0)
  • 2021-02-10 16:50

    The SwiftUI community hasn't really established any best-practices yet because the technology is so new. My answer is based off of what I've seen from different WWDC19 sessions.

    First, create a BindableObject with a categories property. Then write your network request code and set self.categories to your newly downloaded categories.

    import SwiftUI
    import Combine
    
    final class CategoryStore: BindableObject {
        var didChange = PassthroughSubject<Void, Never>()
    
        var categories = [String]()
    
        init() {
            // TODO: Fetch categories from API
            self.categories = ["A", "B", "C"]
        }
    }
    

    Then, add CategoryStore to View and use it with List to iterate over the categories.

    import SwiftUI
    
    struct ContentView : View {
        @ObjectBinding private var store = CategoryStore()
    
        var body: some View {
            List(store.categories.identified(by: \.self)) { category in
                Text(category)
            }
        }
    }
    

    Whenever the categories property updates, your UI will update with the new categories (tysm Combine)

    0 讨论(0)
提交回复
热议问题