在onAppear()中运行函数后,我的@State变量之一不会更新

时间:2020-08-06 00:56:59

标签: swift swiftui

我正在处理使用子弹进行分页的图像轮播。轮播的总宽度和子弹的数量取决于图像的数量。

这是我的vars

struct UserView: View {
    @State var user_id : String = ""
    @State var profilePhotos : [Photo] = []
    @State var pages = 1
}

这是我的onAppear函数

GetProfilePhotos().browseUserPhotos(user_id: self.user_id){(photos) in
    self.profilePhotos = photos
    self.pages = photos.count
}

下游,我使用这些变量来构建轮播。

struct Carousel : UIViewRepresentable {
    
   // .... 
    
    var width : CGFloat
    @Binding var page : Int
    @State var user_id : String
    @Binding var pages : Int
    @Binding var profilePhotos : [Photo]
    var height : CGFloat
    
    func makeUIView(context: Context) -> UIScrollView{
       
        let total = width * CGFloat(self.pages)
        let view = UIScrollView()
        view.isPagingEnabled = true
        view.contentSize = CGSize(width: total, height: 1.0)
        view.bounces = true
        view.showsVerticalScrollIndicator = false
        view.showsHorizontalScrollIndicator = false
        view.delegate = context.coordinator

        let view1 = UIHostingController(rootView: ListCards(page: self.$page, profilePhotos: self.$profilePhotos))
        view1.view.frame = CGRect(x: 0, y: 0, width: total, height: self.height)
        view1.view.backgroundColor = .clear
        
        view.addSubview(view1.view)

        return view
    }
    
    // ...
}

self.profilePhotos很好。我可以毫无问题地读出图像。 self.pages始终设置为1。即使我使用相同的过程来更新两个变量,它也永远不会改变。

任何人都可以解释我所缺少的吗?

下面是我的ListCard

struct ListCards: View {
    @Binding var page : Int
    @Binding var profilePhotos : [Photo]
    
    var body: some View{
        HStack(spacing:0){
            ForEach(self.profilePhotos){photo in
                Card(page: self.$page, width: UIScreen.main.bounds.width, data: photo)
            }
        }.onAppear(){
            print(self.profilePhotos)
        }
   }
}

1 个答案:

答案 0 :(得分:1)

在可表示形式中,您必须将依赖于绑定的代码移到updateUIView中,因为这是每当绑定发生更改时就会调用的方法。

这是一种正确的方法(由于缺少依赖实体而未经测试,因此您可能需要对其进行调整)

struct Carousel : UIViewRepresentable {

   // ...

    var width : CGFloat
    @Binding var page : Int
    @State var user_id : String
    @Binding var pages : Int
    @Binding var profilePhotos : [Photo]
    var height : CGFloat

    func makeUIView(context: Context) -> UIScrollView{

        let view = UIScrollView()
        view.isPagingEnabled = true
        view.bounces = true
        view.showsVerticalScrollIndicator = false
        view.showsHorizontalScrollIndicator = false
        view.delegate = context.coordinator

        return view
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        uiView.subviews.last?.removeFromSuperview()

        let total = width * CGFloat(self.pages)
        uiView.contentSize = CGSize(width: total, height: 1.0)

        let view1 = UIHostingController(rootView: ListCards(page: self.$page, profilePhotos: self.$profilePhotos))
        view1.view.frame = CGRect(x: 0, y: 0, width: total, height: self.height)
        view1.view.backgroundColor = .clear

        uiView.addSubview(view1.view)
    }
}

此外,任何API回调都可能在未知的后台队列上执行,但是状态最好在UI队列上更新,所以

GetProfilePhotos().browseUserPhotos(user_id: self.user_id){(photos) in
  DispatchQueue.main.async {    // redirect to main queue
    self.profilePhotos = photos
    self.pages = photos.count
  }
}