将observedObject放入List

Posted

技术标签:

【中文标题】将observedObject放入List【英文标题】:put observedObject in List 【发布时间】:2020-01-13 20:00:40 【问题描述】:

我从我的 api 获取数据并为它们创建一个类。我可以使用 swifyJSON 正确初始化它们。问题是当我将observedObject 放入List 时,它只能正确显示一次。我改变视图后它会崩溃。它非常强大,因为我的其他具有类似数据结构的列表可以工作。(此视图位于 tabView 中)有人知道我的 getAllNotification() 应该将 view.onAppear() 或 List.onAppear() 放在哪里吗?谢谢!!

class ManagerNotification : Identifiable, ObservableObject
@Published var id = UUID()
var notifyId : Int = 0
var requestId : Int = 0
var requestName: String = ""
var groupName : String = ""
//        var imageName: String  return name 

init(jsonData:JSON) 
    notifyId = jsonData["notifyId"].intValue
    requestId = jsonData["requestId"].intValue
    requestName = jsonData["requestName"].stringValue
    groupName = jsonData["groupName"].stringValue

import SwiftUI
import SwiftyJSON


struct NotificationView: View 
var roles = ["userNotification", "managerNotification"]
@EnvironmentObject var userToken:UserToken

@State var show = false
@State private var selectedIndex = 0

@State var userNotifications : [UserNotification] = [UserNotification]()
@State var managerNotifications : [ManagerNotification] = [ManagerNotification]()

var body: some View 


        VStack 
            Picker(selection: $selectedIndex, label: Text(" ")) 
                        ForEach(0..<roles.count)  (index) in
                            Text(self.roles[index])
                        
                    
            .pickerStyle(SegmentedPickerStyle())
            containedView()
            Spacer()

    
               .onAppear(perform: getAllNotification)


func containedView() -> AnyView 
   switch selectedIndex 
   case 0:
       return AnyView(
            List(userNotifications)  userNotification in
                UserNotificationCellView(userNotification: userNotification)
            
        )

   case 1:

      return AnyView(
        List(managerNotifications)  managernotification in
          ManagerNotificationCellView(managerNotification : managernotification)
        
        .onAppear(perform: getManagerNotification)


    )

   default:
    return AnyView(Text("22").padding(40))
    



func getAllNotification()
//        if (self.userNotifications.count != 0)
//            self.userNotifications.removeAll()
//        
//    I think the crash was in here, because when i don't use removeAll().
//    It works fine, but i don't want every times i change to this view. my array will be longer and 
//    longer

      if (self.managerNotifications.count != 0)
          self.managerNotifications.removeAll()
      

    NetWorkController.sharedInstance.connectApiByPost(api: "/User/email", params: ["token": "\(self.userToken.token)"])
    (jsonData) in
        if let result = jsonData["msg"].string
            print("eeee: \(result)")
            if(result == "you dont have any email")

            else if(result == "success get email")
                if let searchResults = jsonData["mail"].array 
                    for notification in searchResults 
                        self.userNotifications.append(UserNotification(jsonData: notification))
                    
                
            
        

    

    NetWorkController.sharedInstance.connectApiByPost(api: "/Manager/email", params: ["token": "\(self.userToken.token)"])
           (jsonData) in
               if let result = jsonData["msg"].string
                   print("eeee: \(result)")
                   if(result == "you dont have any email")

                   else if(result == "success get email")
                       if let searchResults = jsonData["mail"].array 
                           for notification in searchResults 
                               self.managerNotifications.append(ManagerNotification(jsonData: notification))
                           
                       

                   
               

           


func getManagerNotification()

//        if (self.managerNotifications.count != 0)
//            self.managerNotifications.removeAll()
//        
    print(self.managerNotifications.count)
    NetWorkController.sharedInstance.connectApiByPost(api: "/Manager/email", params: ["token": "\(self.userToken.token)"])
    (jsonData) in
        if let result = jsonData["msg"].string
            print("eeee: \(result)")
            if(result == "you dont have any email")

            else if(result == "success get email")
                if let searchResults = jsonData["mail"].array 
                    for notification in searchResults 
                        self.managerNotifications.append(ManagerNotification(jsonData: notification))
                    
                
            
        

    

错误信息

仅警告一次:UITableView 被告知要在视图层次结构中布局其可见单元格和其他内容(表格视图或其超级视图之一尚未添加到窗口中)。这可能会在没有准确信息的情况下强制表视图内的视图加载和执行布局(例如,表视图边界、特征集合、布局边距、安全区域插入等),从而导致错误,并且还会由于额外的布局传递而导致不必要的性能开销.在 UITableViewAlertForLayoutOutsideViewHierarchy 处创建一个符号断点,以便在调试器中捕获此问题并查看导致此问题发生的原因,因此如果可能,您可以完全避免此操作,或者将其推迟到表格视图添加到窗口中。原因:'尝试删除第0节,但更新前只有0节'

【问题讨论】:

【参考方案1】:

我想你对@State@ObservebableObject的作用感到困惑;它不像 MVC,你用 SwiftUI.View 替换 ViewController,因为它看起来你正在尝试在你的示例中做。相反,视图应该是某个本地@State 和/或外部@ObservedObject 的函数。这更接近于 MVVM,您的 @ObservedObject 类似于 ViewModel,并且视图将重建自身以响应 ObservableObject@Published 属性的变化。

TLDR:将您的获取逻辑移动到 ObservableObject 并使用 @Published 允许视图订阅结果。我这里有一个例子:https://github.com/joshuajhomann/TVMaze-SwiftUI-Navigation

【讨论】:

感谢您的评论,我是 SwiftUI 初学者。我通过将 getAllNotivfication() 放在 NotificationView 的 var body onAppear 中得到了解决方法。它不会再崩溃了。谢谢

以上是关于将observedObject放入List的主要内容,如果未能解决你的问题,请参考以下文章

@ObservedObject 更改后 SwiftUI 视图未更新

ObservedObject 未触发视图重绘

SwiftUI 不会将状态更新为 @ObservedObject cameraViewModel 对象

核心数据 NSManagedObject - ObservedObjects 未更新

从函数内部的 ObservedObjects 访问已发布的变量

极简示例揭示 SwiftUI 中 @ObservedObject 与 @StateObject 状态的关键区别