我正在尝试为“本周”和“下周”制作一个带有控制器的待办事项应用程序。 (日期在本周的对象将显示在 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 控制器中创建对象时,则日期从本周更改为下周
答案 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.vc1
、GlobalVCs.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)
}
}