1

So I have a few data fetching tasks for views (type: View)that need to be run as soon as a view is loaded. If I put them in .onAppear{}, they don't load at the right time. So I must put them in the init(){} block of the struct.

Also, I have data fetching tasks from view models. These also need to be run instantly, and if I call them in .onAppear{}, it's too late and the program won't load the data. So I put those functions in the init(){} block as well.

Here's the problem. It initializes like a HUGE amount of times. I have 3K reads a day on Firestore and I'm the only one using the app. When I connect my voice chat app, it joins the channel on init(){} but then it tries to join it like 17 more times.

So my question is: How do I call a function simultaneous to the View's initialization, but make sure it only runs once per loading of the view?

Here's some examples from my code to give further insight

struct VoiceChatView: View {
    @State var halfModalShown = false
    @State var settingsModalShown = false
    @Binding var topic : Topic
    @State var channel : Channel
    
    @State var isLocalAudioMuted = false
    private let audioEngine = AudioEngine()
    private var rtcEngine: AgoraRtcEngineKit {
        get {
            return audioEngine.agoraKit
        }
    }
    
    @State var currentUser = AuthViewModel.shared.user!
    
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
    init(topic: Binding<Topic>, channel: Channel) {
        self._topic = topic
        self._channel = State(initialValue: channel)
        self.callOnce()
    }


    var body: some View {
        Text("Hello, world")
    }
}

If you look at callOnce() you'll notice it's being called multiple times. I need that to be called before anything else happens, yes. But I need it not to continuously call over and over.

  • 4
    You need to separate your model from your view. Views are structs. They should be lightweight and disposable; SwiftUI will create and dispose of your views as required. Your model will typically be a class. It will have a longer lifetime. You inject your model into your view either by passing it as a parameter or by using the environment. A SwiftUI view should not need an `init`. Even `onAppear` won't be needed in many cases – Paulw11 Mar 08 '21 at 01:43

2 Answers2

1

Can you try the wording in init method

   init(topic: Binding<Topic>, channel: Channel) {
            self._topic = topic
            self._channel = State(initialValue: channel)
//            self.callOnce()
        if self._channel {
            self.callOnce()
        }
        }
Geek__Lee
  • 247
  • 1
  • 7
0

You can put your function or works that you are doing in init of your View, in init of your class/model. never use View init for this kind of works, SwiftUI just initialize Views here and there and any time it thinks it must, so Never Ever do that.

Even if you could define a condition for controlling some data! this is Wrong code design!

You can put a condition that your Views waits for your class to start rendering in case also.

ios coder
  • 1
  • 4
  • 31
  • 91