如何从不同的控制器重新加载 UITableView

时间:2021-02-06 02:19:05

标签: ios swift

我正在尝试为“本周”和“下周”制作一个带有控制器的待办事项应用程序。 (日期在本周的对象将显示在 thisWeek 视图控制器中,而具有下周日期的对象将显示在 nextWeek 视图控制器中。但是,有时对象不会出现在直到应用程序重新启动,我不确定为什么会发生这种情况或如何解决它。

我的理论是每次添加/更改数据时都需要重新加载不同控制器中的每个表。我只是不知道如何从与我所在的控制器不同的控制器访问该表。

尝试 1 我尝试使用如下所示的单例:

class ToDoTables {
    private init() {}

    static let shared = ToDoTables()

    lazy var thisTable: UITableView = {
        let thisWeek = UITableView()

        return thisWeek
    }()
    
    lazy var nextTable: UITableView = {
        let nextWeek = UITableView()

        return nextWeek
    }()
}

然后被称为:

let thisTable = ToDoTables.shared.thisTable

但是这不起作用,因为我最初使用情节提要创建了表格,并且只在控制器中使用了 IBOutlet,并且无法找到保持插座并使用单例的方法。接下来,我尝试移除插座并仅使用上面的代码。当我模拟应用程序时,它崩溃了,因为找不到插座或类似的东西(这是预期的)。

尝试 2 我试图通过创建 vc 的实例并以这种方式访问​​表来访问另一个控制器的表:

NextWeekController().nextTable.reloadData()

但得到一个错误,提示“在隐式解包可选值时意外发现 nil”

所以我不确定这是我的表每次都需要重新加载,还是其他原因。


无效操作概述(需要重启应用,或者需要再次加载控制器/表):

  • 在 nextWeek 控制器中创建的带有当前周日期的内容不会出现

  • 在 nextWeek 控制器中创建对象时,则日期从下周更改为本周

  • 在 thisWeek 控制器中创建的下周日期不会出现

  • 当在 thisWeek 控制器中创建对象时,则日期从本周更改为下周

2 个答案:

答案 0 :(得分:0)

<块引用>

我的理论是每次添加/更改数据时都需要重新加载不同控制器中的每个表。

你说得对。对于 UITableView.reloadData(),Apple Docs 声明为:

<块引用>

调用此方法重新加载用于构造 表

也就是说,如果数据发生变化,需要用这个方法重新加载table view的数据。


<块引用>

我只是不知道如何从不同的控制器访问表 比我所在的那个。

一种解决方案是通过一个共享实例创建对所有视图控制器的全局引用。

// GlobalVCs.swift

class GlobalVCs {
  static var shared = GlobalVCs()

  var nameOfVC1!
  var nameOfVC2!
  var nameOfVC3!
  // and so on

  private init() {}
}

然后从每个视图控制器的 viewDidLoad() 方法设置全局 vc 引用。

示例:

// VC1.swift

override func viewDidLoad() {
  GlobalVCs.shared.vc1 = self
}

然后你可以在任何地方使用 GlobalVCs.shared.vc1GlobalVCs.shared.vc2 等访问视图控制器

答案 1 :(得分:0)

对不起,但需要说这是错误的方法。我们需要遵循 MCV 模型,其中我们有数据模型、视图和控制器。如果您以待办事项模型为例,您可以:

import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift

struct ToDoItem: Codable, Identifiable {

    static let collection = "todos"

    @DocumentID var id: String?
    
    var uid: String;
    var done: Bool;
    var timestamp: Timestamp;
    var description: String
    
}

那么你需要有这种类型数据的存储库,例如,如果我们使用 Firebase,我们可以拥有

import Foundation
import Combine

import FirebaseFirestore
import FirebaseFirestoreSwift

class BaseRepository<T> {
    
    @Published var items = Array<T>()
    
    func add(_ item: T) { fatalError("This method must be overridden") }
    func remove(_ item: T) { fatalError("This method must be overridden") }
    func update(_ item: T) { fatalError("This method must be overridden") }
    
}

然后我们有 ToDoRepository(单个对象)

import Foundation
import FirebaseFirestore
import FirebaseFirestoreSwift
import Resolver
import CoreLocation
import Combine

class ToDoRepository: BaseRepository<ToDoItem>, ObservableObject {
    
    var db = Firestore.firestore()



    uid: String? {
       didSet {
          load()
       }
    }
     
    private func load() {
        db.collection(ToDoItem.collection).whereField("uid", isEqualTo: uid).order(by: "timestamp").addSnapshotListener {
            ( querySnapshot, error ) in
            if let querySnapshot = querySnapshot {
                self.items = querySnapshot.documents.compactMap { document -> ToDoItem? in
                    try? document.data(as: ToDoItem.self)
                }
            }
        }
    }

}

现在我们需要在 AppDelegate+Injection.swift 中注册仓库:

import Foundation
import Resolver

extension Resolver: ResolverRegistering {
  public static func registerAllServices() {
    // Services
    
    register { ToDoRepository() }.scope(application)
  }
}

之后我们可以在任何控制器中使用 ToDoRepository :

import UIKit
import Combine
import Resolver

class MyController: UIViewController {

     private var cancellables = Set<AnyCancellable>()
     @LazyInjected var toDoRepository: ToDoRepository

     // and listen and update any table view like this 
     override func viewDidLoad() {
        super.viewDidLoad()
        
        toDoRepository.$items
            .receive(on: DispatchQueue.main)
            .sink { [weak self] todos 
                self?.todos = todos
                tableView.reloadData()
            }
            .store(in: &cancellables)
     }
}