【发布时间】:2019-10-08 23:51:21
【问题描述】:
在RxSwift 的帮助下,构建一个使用Alamofire 和Realm 分别进行网络调用和数据存储的应用程序。一切正常,但当天的需要是防止总是刷新网络调用的视图。现在应用程序的行为就像我将 JSON 响应复制到数据库,然后从数据库更新视图。但是要始终获得最新的响应,应用程序需要在每个 viewWillAppear 上调用网络 API。但是我不想获取所有数据库数据并搜索新响应是否有任何更改然后显示它。那么Swift 或 Alamofire 或 Realm 中是否有任何东西可以让我观察到数据是否与之前加载到数据库中的数据不同,然后只有应用程序会更新其视图。
self?.notificationToken = Database.singleton.fetchStudentsForAttendence(byCLassId: classId).observe { [weak self] change in
switch change {
case .initial(let initial):
TestDebug.debugInfo(fileName: "", message: "INIT: \(initial)")
self!.viewModel.getStudentsData(id: classId)
case .update(_, let deletions, let insertions, let modifications):
print(modifications)
TestDebug.debugInfo(fileName: "", message: "MODIFY: \(modifications)")
TestDebug.debugInfo(fileName: "", message: "MODIFY: \(insertions)")
case .error(let error):
TestDebug.debugInfo(fileName: "", message: "ERROR:\(error)")
}
}
这就是我现在观察数据的方式,但是当我每次调用 API 时,我都会将响应保存到数据库中,并且我使用 case .initial 来监控它,因为数据库总是被刷新并且每次都会调用这个块.我需要一些东西来监控数据库中数据值的变化。 Realm 中有什么东西吗?
好的,我正在这样做,有一个 viewController,其中我有一个容器视图,其中包含 Collection 视图作为子视图。
private lazy var studentsViewController: AttandenceView = {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "attendenceCV") as! AttandenceView
self.add(asChildViewController: viewController, to: studentsView)
return viewController
}() //this way I am adding collectionView's container view.
这是我从中获取数据并为 CollectionView 创建可观察对象的 ViewModel 代码。
class AttendenceVM {
//MARK: Properties
let disposeBag = DisposeBag()
let studentCells = BehaviorRelay<[StudentModel]>(value: [])
var studentCell : Observable<[StudentModel]> {
return studentCells.asObservable().debug("CELL")
}
var notificationToken : NotificationToken? = nil
deinit {
notificationToken?.invalidate()
}
func getStudentsData(id: Int) {
let studentsData = (Database.singleton.fetchStudentsForAttendence(byCLassId: id))
self.notificationToken = studentsData.observe{[weak self] change in
TestDebug.debugInfo(fileName: "", message: "Switch:::: change")
switch change {
case .initial(let initial):
TestDebug.debugInfo(fileName: "", message: "INIT: \(initial)")
self!.studentCells.accept(Array(studentsData))
case .update(_, let deletions, let insertions, let modifications):
TestDebug.debugInfo(fileName: "", message: "MODIF::: \(modifications)")
self!.studentCells.accept(Array(studentsData))
case .error(let error):
print(error)
}
}
//self.studentCells.accept(studentsData)
}
}
然后我在它的类中分别填充collectionView,通过这样做。
class AttandenceView: UIViewController, UICollectionViewDelegateFlowLayout {
//MARK: - Outlets
@IBOutlet weak var studentsView: UICollectionView!
let studentCells = BehaviorRelay<[StudentModel]>(value: [])
let scanStudentCells = BehaviorRelay<[ClassStudent]>(value: [])
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let flowLayout = UICollectionViewFlowLayout()
let size = CGSize(width: 105, height: 135)
flowLayout.itemSize = size
studentsView.setCollectionViewLayout(flowLayout, animated: true)
studentsView.rx.setDelegate(self).disposed(by: disposeBag)
setupBinding()
}
func setupBinding() {
studentsView.register(UINib(nibName: "StudentCVCell", bundle: nil), forCellWithReuseIdentifier: "studentCV")
//Cell creation
scanStudentCells.asObservable().debug("Cell Creation").bind(to: studentsView.rx.items(cellIdentifier: "studentCV", cellType: StudentCVCell.self)) {
(row , element, cell) in
if (element.attandance == 1 ) {
// update view accordingly
} else if (element.attandance == 0) {
// update view accordingly
} else if (element.attandance == 2) {
// update view accordingly
}
cell.viewModel2 = element
}.disposed(by: disposeBag)
//Item Display
studentsView.rx
.willDisplayCell
.subscribe(onNext: ({ (cell,indexPath) in
cell.alpha = 0
let transform = CATransform3DTranslate(CATransform3DIdentity, -250, 0, 0)
cell.layer.transform = transform
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
cell.alpha = 1
cell.layer.transform = CATransform3DIdentity
}, completion: nil)
})).disposed(by: disposeBag)
// item selection with model details.
Observable
.zip(
studentsView
.rx
.itemSelected,
studentsView
.rx
.modelSelected(StudentModel.self))
.bind { [weak self] indexPath, model in
let cell = self?.studentsView.cellForItem(at: indexPath) as? StudentCVCell
if (model.attandance == 0) {
// update view accordingly
} else if (model.attandance == 1) {
// update view accordingly
} else if (model.attandance == 2) {
// update view accordingly
}
}.disposed(by: disposeBag)
}
以下是主视图控制器的完整代码
class AttendanceViewController: MainViewController {
let viewModel: AttendenceVM = AttendenceVM()
private let disposeBag = DisposeBag()
let appDelegate = (UIApplication.shared.delegate as! AppDelegate)
let notificationCenter = NotificationCenter.default
var students : Results<StudentModel>? = nil
var notificationToken: NotificationToken? = nil
private lazy var studentsViewController: AttandenceView = {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "attendenceCV") as! AttandenceView
self.add(asChildViewController: viewController, to: studentsView)
return viewController
}()
override func viewDidLoad() {
super.viewDidLoad()
if AppFunctions.getAssignedClassId(forKey: "assignedClassId") != 0 { // && pref id isAssigned == true
let id = AppFunctions.getAssignedClassId(forKey: "assignedClassId")
self.viewModel.getStudentsData(id: id)
}
bindViewModel()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
classNameLbl.text = "Attandence: Class \(AppFunctions.getAssignedClassName(forKey: "assignedClassName"))"
students = Database.singleton.fetchStudents(byAttandence: 0, byclassId: AppFunctions.getAssignedClassId(forKey: "assignedClassId"))
notificationToken = students?.observe {[weak self] change in
self!.studentAbsentLbl.text = "Students Absent (\(String(describing: self!.students!.count)))"
}
if AppFunctions.getAssignedClassId(forKey: "assignedClassId") != 0 { // && pref id isAssigned == true
let id = AppFunctions.getAssignedClassId(forKey: "assignedClassId")
getAssignedClassData(classId: id)
}
}
deinit {
notificationToken?.invalidate()
}
func getAssignedClassData(classId: Int) {
return APIService.singelton
.getClassById(classId: classId)
.subscribe({ [weak self] _ in
TestDebug.debugInfo(fileName: "", message: "\(classId)")
// self?.notificationToken = Database.singleton.fetchStudentsForAttendence(byCLassId: classId).observe { [weak self] change in
// switch change {
// case .initial(let initial):
// TestDebug.debugInfo(fileName: "", message: "INIT: \(initial)")
// //self!.viewModel.getStudentsData(id: classId)
// case .update(_, let deletions, let insertions, let modifications):
// print(modifications)
// TestDebug.debugInfo(fileName: "", message: "MODIFY: \(modifications)")
// TestDebug.debugInfo(fileName: "", message: "MODIFY: \(insertions)")
// case .error(let error):
// TestDebug.debugInfo(fileName: "", message: "ERROR:\(error)")
// }
// }
})
.disposed(by: self.disposeBag)
}
func bindViewModel() {
viewModel
.studentCell
.asObservable()
.observeOn(MainScheduler.instance)
.bind(to: studentsViewController.studentCells)
.disposed(by: disposeBag)
}
}
【问题讨论】:
-
使用领域通知。
-
能带来什么改变?能详细点吗
-
这是我最喜欢的 Realm 功能。您设置观察者,并且任何时候数据更改视图都会更新。有一些很棒的教程可用。
-
好的,我会试试的。感谢您的信息
-
嗨,还需要问一件事吗?
标签: swift realm alamofire rx-swift