简体   繁体   中英

Pass data from model to view in SwiftUI

  • How do I get the data from the CameraService after the videoClips array is populated from a button in the CameraView.

  • I would like to be able to press a button and move to a new screen passing along an array of AVPlayerItems.

  • My button always prints 0 even after I know there is data in the array in the CameraService

public class CameraService: NSObject, AVCaptureFileOutputRecordingDelegate {
     
  @Published public var videoClips = [AVPlayerItem]()

  public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    let video: AVPlayerItem = AVPlayerItem(url:outputFileURL)
    videoClips.append(video)
  }
}

final class CameraModel: ObservableObject {
    
  private let service = CameraService()
  var videoClips: [AVPlayerItem]

  init() {   
    videoClips = service.videoClips
  }
}

struct CameraView: View {
    
  @StateObject var model = CameraModel()

  var body: some View {
    Button("video") {
      print(model.videoClips.count)
    }
  }
}

In its current form, model.videoClips.count will only ever be 0, because you set videoClips in init() and then it never gets updated again.

I'm guessing that you're assuming it'll be updated because CameraService.videoClips is a @Published property. But, @Published only gets watched automatically by View s and their ObservableObject s. So, two problems here: a) CameraService is not an ObservableObject and CameraModel is not a View .

My first recommendation fix this would be to ditch CameraModel completely. Maybe it's a function of trying to make a minimal example, but in its current form, it's not doing anything -- it's just a non-functional middleman. So, turn CameraService into an ObservableObject , which would mean that the @Published property would work and you'd be good-to-go.

Regarding the navigation to another screen, that's probably best for a separate question, but I'll leave a brief answer here:

//in your view
NavigationLink(destination: DetailView(videoClips: service.videoClips)) {
  Text("Link")
} 

(This is assuming you've turned CameraService into your ObservableObject )

If for some reason you did need both CameraModel and CameraService , you can hook up the two by doing something like this:

class CameraModel : ObservableObject {
    private let service = CameraService()
    @Published var videoClips : [AVPlayerItem] = [] //note that this is @Published now
        
    init() {
        service.$videoClips.assign(to: &self.$videoClips) //use a Combine Publisher to get updates from the CameraService videoClips and assign them to this class's videoClips any time there's an update 
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM