Один из моих переменных @State не обновляется после запуска функции в onAppear () - PullRequest
1 голос
/ 06 августа 2020

Я работаю с каруселью изображений, в которой для нумерации страниц используются маркеры. Общая ширина карусели и количество маркеров зависят от количества изображений.

Вот мои вары

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
}

Downstream, я использую эти переменные для построения карусели.

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 Ответ

1 голос
/ 06 августа 2020

В представлении вы должны переместить зависимый от привязки код в 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 может выполняться в неизвестной фоновой очереди, но состояния лучше обновлять в очереди пользовательского интерфейса, поэтому

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