簡體   English   中英

上出現 SwiftUI iOS 14.4

[英]onAppear SwiftUI iOS 14.4

我想在選擇目的地時顯示旅游目的地的詳細信息。 下面是我創建的語法,我調用self.presenter.getDetail(request: destination.id)這是 in.onAppear,當程序啟動並按下目的地時,xcode 說self.presenter.detailDestination..like沒有'不存在或為零。 即使我插入 print ("TEST") 發生的錯誤是來自 self.presenter.detailDestination 的錯誤 nil self.presenter.detailDestination..like

struct DetailView: View {
  @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
  @State private var showingAlert = false
  @ObservedObject var presenter: GetDetailPresenter<
    Interactor<String, DestinationDomainModel, GetDetailDestinationRepository<
        GetDestinationLocaleDataSource, GetDetailDestinationRemoteDataSource,
        DetailDestinationTransformer>>,
    Interactor<String, DestinationDomainModel, UpdateFavoriteDestinationRepository<
        FavoriteDestinationLocaleDataSource, DetailDestinationTransformer>>>
  
  var destination: DestinationDomainModel
  
  var body: some View {
    ZStack {
      if presenter.isLoading {
        loadingIndicator
      } else {
        ZStack {
          GeometryReader { geo in
            ScrollView(.vertical) {
              VStack {
                self.imageCategory
                  .padding(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 0))
                  .frame(width: geo.size.width, height: 270)
                
                self.content
                  .padding()
              }
            }
          }
          .edgesIgnoringSafeArea(.all)
          .padding(.bottom, 80)
          
          VStack {
            Spacer()
            favorite
              .padding(EdgeInsets.init(top: 0, leading: 16, bottom: 10, trailing: 16))
          }
        }
      }
    }
    .onAppear {
      self.presenter.getDetail(request: destination.id)
    }
    .navigationBarBackButtonHidden(true)
    .navigationBarItems(leading: btnBack)
  }
}

extension DetailView {
  var btnBack : some View { Button(action: {
    self.presentationMode.wrappedValue.dismiss()
  }) {
    HStack {
      Image(systemName: "arrow.left.circle.fill")
        .aspectRatio(contentMode: .fill)
        .foregroundColor(.black)
      Text("Back")
        .foregroundColor(.black)
    }
   }
  }
  
  var spacer: some View {
    Spacer()
  }
  
  var loadingIndicator: some View {
    VStack {
      Text("Loading...")
      ActivityIndicator()
    }
  }
  
  var imageCategory: some View {
    WebImage(url: URL(string: self.destination.image))
      .resizable()
      .indicator(.activity)
      .transition(.fade(duration: 0.5))
      .aspectRatio(contentMode: .fill)
      .frame(width: UIScreen.main.bounds.width, height: 270, alignment: .center)
      .clipShape(RoundedCorner(radius: 30, corners: [.bottomLeft, .bottomRight]))
  }
  
  var header: some View {
    VStack(alignment: .leading) {
      Text("\(self.presenter.detailDestination!.like) Peoples Like This")
        .padding(.bottom, 10)
      
      Text(self.presenter.detailDestination!.name)
        .font(.largeTitle)
        .bold()
        .padding(.bottom, 5)
      
      Text(self.presenter.detailDestination!.address)
        .font(.system(size: 18))
        .bold()
      
      Text("Coordinate: \(self.presenter.detailDestination!.longitude), \(self.presenter.detailDestination!.latitude)")
        .font(.system(size: 13))
    }
  }
  
  var favorite: some View {
    Button(action: {
      self.presenter.updateFavoriteDestination(request: String(self.destination.id))
      
      self.showingAlert.toggle()
    }) {
      if self.presenter.detailDestination!.isFavorite == true {
        Text("Remove From Favorite")
          .font(.system(size: 20))
          .bold()
          .onAppear {
            self.presenter.getDetail(request: destination.id)
          }
      } else {
        Text("Add To Favorite")
          .font(.system(size: 20))
          .bold()
      }
    }
    .alert(isPresented: $showingAlert) {
      if self.presenter.detailDestination!.isFavorite == true {
        return Alert(title: Text("Info"), message: Text("Destination Has Added"),
                     dismissButton: .default(Text("Ok")))
      } else {
        return Alert(title: Text("Info"), message: Text("Destination Has Removed"),
                     dismissButton: .default(Text("Ok")))
      }
    }
    .frame(width: UIScreen.main.bounds.width - 32, height: 50)
    .buttonStyle(PlainButtonStyle())
    .foregroundColor(Color.white)
    .background(Color.red)
    .cornerRadius(12)
  }
  
  var description: some View {
    VStack(alignment: .leading) {
      Text("Description")
        .font(.system(size: 17))
        .bold()
        .padding(.bottom, 7)
      
      Text(self.presenter.detailDestination!.placeDescription)
        .font(.system(size: 15))
        .multilineTextAlignment(.leading)
        .lineLimit(nil)
        .lineSpacing(5)
    }
  }
  
  var content: some View {
    VStack(alignment: .leading, spacing: 0) {
      header
        .padding(.bottom)
      description
    }
  }
}

onAppear在第一次渲染期間被調用。 這意味着視圖層次結構中引用的任何值(在本例中為detailDestination )都將在此傳遞期間呈現 - 而不僅僅是onAppear之后。

在您的header中,您指的是self.presenter.detailDestination..like 在第一次渲染時,不能保證onAppear會在您強制展開detailDestination之前完成它的操作

如果detailDestination存在,最簡單的解決方案可能是僅有條件地渲染視圖的 rest。 看起來您已經在嘗試使用isLoading執行此操作,但是狀態一定不匹配——我的猜測是在isLoading甚至設置為 true 之前。

因此,您的內容視圖可能類似於:

if self.presenter.detailDestination != nil {
   VStack(alignment: .leading, spacing: 0) {
      header
        .padding(.bottom)
      description
    }
} else {
  EmptyView()
} 

這一切都假設您的presenter具有 @Published 屬性,該屬性將在實際加載detailDestination時觸發當前組件的重新渲染。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM