[英]Don't know where to place saveData to save data with userDefaults in Swift
I'm trying to save my data after being changed by the user, the thing im saving the data from my model also im fetching the data from my model class, I would like to save the data once the viewwilldissappear so all the data will be saved and I can fetch the data from my model(when I init it again), I kinda lost the way with implementing it:\ Here's my VC Code: where i set up my tableView cells + would like to use saveData() there:我正在尝试在用户更改后保存我的数据,我正在从我的 model 中保存数据,我也正在从我的 model class 中获取数据保存,我可以从我的模型中获取数据(当我再次初始化它时),我有点迷失了实现它的方式:\ 这是我的 VC 代码:我在哪里设置我的 tableView 单元格 + 想在那里使用 saveData() :
import UIKit
import PanModal
class FilterTableViewController: UIViewController, UITableViewDelegate,UITableViewDataSource, PanModalPresentable {
//Instance of our ViewModel
private var filterViewModel = FilterViewModel()
//Our Model Instance:
// private var filterModel = FilterModel()
let tableView = UITableView()
var safeArea: UILayoutGuide!
let buttonView = UIView()
var panScrollable: UIScrollView? {
return tableView
}
var albumsPickerIndexPath: IndexPath? // indexPath of the currently shown albums picker in tableview.
// var delegate: FilterTableViewDelegate?
var datesCell = DatesCell()
var selectedAlbumByUser = ""
// var userFilter: FilterModel?
override func viewDidLoad() {
super.viewDidLoad()
safeArea = view.layoutMarginsGuide
setupTableView()
self.tableView.dataSource = self
self.tableView.delegate = self
setupButtonView()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
// MARK: - Views Configurations
func setupTableView() {
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 120).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.separatorStyle = .singleLine
tableView.isScrollEnabled = false
tableView.allowsSelection = true
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 600
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
tableView.tableFooterView = UIView(frame: .zero)
}
func setupButtonView() {
view.addSubview(buttonView)
buttonView.translatesAutoresizingMaskIntoConstraints = false
buttonView.backgroundColor = .white
buttonView.layer.cornerRadius = 15;
// buttonView.clipsToBounds = true
NSLayoutConstraint.activate([
buttonView.topAnchor.constraint(equalTo: tableView.bottomAnchor),
buttonView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor,constant: 10),
buttonView.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 16),
buttonView.trailingAnchor.constraint(equalTo: view.trailingAnchor,constant: -16),
buttonView.widthAnchor.constraint(equalToConstant: 100),
buttonView.heightAnchor.constraint(equalToConstant: 40),
])
let applyFiltersButton = UIButton()
applyFiltersButton.setTitle("Apply Filters", for: .normal)
applyFiltersButton.setTitleColor(.white, for: .normal)
applyFiltersButton.layer.cornerRadius = 15;
// myFirstButton.clipsToBounds = true
applyFiltersButton.backgroundColor = #colorLiteral(red: 0.1957295239, green: 0.6059523225, blue: 0.960457623, alpha: 1)
applyFiltersButton.contentHorizontalAlignment = .center;
applyFiltersButton.titleLabel?.font = UIFont(name: "Helvetica", size:16)
self.buttonView.addSubview(applyFiltersButton)
applyFiltersButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
applyFiltersButton.topAnchor.constraint(equalTo: buttonView.topAnchor),
applyFiltersButton.bottomAnchor.constraint(equalTo: buttonView.bottomAnchor),
applyFiltersButton.leadingAnchor.constraint(equalTo: buttonView.leadingAnchor),
applyFiltersButton.trailingAnchor.constraint(equalTo: buttonView.trailingAnchor),
applyFiltersButton.widthAnchor.constraint(equalToConstant: 100),
applyFiltersButton.heightAnchor.constraint(equalToConstant: 40),
applyFiltersButton.centerXAnchor.constraint(equalTo: buttonView.centerXAnchor),
applyFiltersButton.centerYAnchor.constraint(equalTo: buttonView.centerYAnchor)
])
}
func indexPathToInsertDatePicker(indexPath: IndexPath) -> IndexPath {
if let albumsPickerIndexPath = albumsPickerIndexPath, albumsPickerIndexPath.row < indexPath.row {
return indexPath
} else {
return IndexPath(row: indexPath.row + 1, section: indexPath.section)
}
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If datePicker is already present, we add one extra cell for that
if albumsPickerIndexPath != nil {
return 5 + 1
} else {
return 5
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let byActivityCell = UINib(nibName: "byActivityCell",bundle: nil)
self.tableView.register(byActivityCell,forCellReuseIdentifier: "byActivityCell")
let activityCell = tableView.dequeueReusableCell(withIdentifier: "byActivityCell", for: indexPath) as! byActivityCell
activityCell.selectionStyle = .none
activityCell.activityDelegate = filterViewModel
return activityCell
case 1:
let byTypeCell = UINib(nibName: "ByType",bundle: nil)
self.tableView.register(byTypeCell,forCellReuseIdentifier: "byTypeCell")
let typeCell = tableView.dequeueReusableCell(withIdentifier: "byTypeCell", for: indexPath) as! ByType
typeCell.selectionStyle = .none
typeCell.byTypeDelegate = filterViewModel
return typeCell
case 2:
let byHashtagsCell = UINib(nibName: "ByHashtags",bundle: nil)
self.tableView.register(byHashtagsCell,forCellReuseIdentifier: "byHashtagsCell")
let hashtagsCell = tableView.dequeueReusableCell(withIdentifier: "byHashtagsCell", for: indexPath) as! ByHashtags
hashtagsCell.selectionStyle = .none
hashtagsCell.byHashtagsDelegate = filterViewModel
return hashtagsCell
case 3:
let byDatesCell = UINib(nibName: "DatesCell",bundle: nil)
self.tableView.register(byDatesCell,forCellReuseIdentifier: "byDatesCell")
let datesCell = tableView.dequeueReusableCell(withIdentifier: "byDatesCell", for: indexPath) as! DatesCell
datesCell.selectionStyle = .none
datesCell.datesTableViewCellDelegate = self
return datesCell
case 4:
let byAlbumCell = UINib(nibName: "AlbumCell",bundle: nil)
self.tableView.register(byAlbumCell,forCellReuseIdentifier: "byAlbumCell")
let albumCell = tableView.dequeueReusableCell(withIdentifier: "byAlbumCell", for: indexPath) as! AlbumCell
// albumCell.configureCell(choosenAlbum: filterViewModel.getSelectedAlbum())
albumCell.selectionStyle = .none
filterViewModel.getAlbum = { selectedAlbum in
albumCell.configureCell(choosenAlbum: selectedAlbum)
}
return albumCell
case 5:
let albumPickerCell = UINib(nibName: "AlbumsPickerTableViewCell", bundle: nil)
self.tableView.register(albumPickerCell, forCellReuseIdentifier: "albumPickerCell")
let albumsPicker = tableView.dequeueReusableCell(withIdentifier: "albumPickerCell", for: indexPath) as! AlbumsPickerTableViewCell
// albumsPicker.albumsPickerCellDelegate = self
albumsPicker.albumsPickerCellDelegate = filterViewModel
return albumsPicker
default:
return UITableViewCell()
}
}
// MARK: TableViewDelegate Methods:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
tableView.beginUpdates()
// 1 - We Delete the UIPicker when the user "Deselect" thr row.
if let datePickerIndexPath = albumsPickerIndexPath, datePickerIndexPath.row - 1 == indexPath.row {
tableView.deleteRows(at: [datePickerIndexPath], with: .fade)
self.albumsPickerIndexPath = nil
let albumCell = tableView.cellForRow(at: indexPath) as! AlbumCell
UIView.animate(withDuration: 1) {
albumCell.arrowPickerView.transform = CGAffineTransform.identity
}
} else {
// 2
// if let datePickerIndexPath = albumsPickerIndexPath {
// tableView.deleteRows(at: [datePickerIndexPath], with: .fade)
// }
let albumCell = tableView.cellForRow(at: indexPath) as! AlbumCell
UIView.animate(withDuration: 1) {
albumCell.arrowPickerView.transform = CGAffineTransform(rotationAngle: .pi)
}
albumsPickerIndexPath = indexPathToInsertDatePicker(indexPath: indexPath)
tableView.insertRows(at: [albumsPickerIndexPath!], with: .fade)
tableView.deselectRow(at: indexPath, animated: true)
}
tableView.endUpdates()
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.row == 4 {
return indexPath
} else {
return nil
}
}
}
extension FilterTableViewController: DatesTableViewCellDelegate {
func didButtonFromPressed() {
let pickerController = CalendarPickerViewController(
baseDate: Date(),
selectedDateChanged: { [weak self] date in
guard let self = self else { return }
// self.item.date = date
// self.filterModel.startDate = date
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
})
present(pickerController, animated: true, completion: nil)
}
func didButtonToPressed() {
//TODO: Present our custom calendar
let calendarController = CalendarPickerViewController(
baseDate: Date(),
selectedDateChanged: { [weak self] date in
guard let self = self else { return }
// self.filterModel.endDate = date
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
})
self.present(calendarController, animated: true, completion: nil)
}
}
Here's my Model:这是我的 Model:
import Foundation
import UIKit
class FilterModel {
let userDefaults = UserDefaults.standard
var byActivity: String = ""
var postType: [String] = []
var hashTags: [String] = []
var startDate: Date = Date()
var endDate: Date = Date()
var album: String = ""
init() {
// First we need to fetch the data from the local storeage and insert into the vars:
self.fetchData()
}
deinit {
//Second we need to save the data in the local storeage:
self.saveData()
print("Im being deinited")
}
// MARK: - UserDefaults Section:
//Fetch - Retrieve from NSUserDefaults(local):
func fetchData() {
self.byActivity = userDefaults.string(forKey: k.UserDefaultsSaveKeys.byActivitySaveKey) ?? self.byActivity
self.postType = userDefaults.stringArray(forKey: k.UserDefaultsSaveKeys.postTypeSaveKey) ?? self.postType
self.hashTags = userDefaults.stringArray(forKey: k.UserDefaultsSaveKeys.hashTagsSaveKey) ?? self.hashTags
self.startDate = userDefaults.object(forKey: k.UserDefaultsSaveKeys.startDateSaveKey) as? Date ?? self.startDate
self.endDate = userDefaults.object(forKey: k.UserDefaultsSaveKeys.endDateSaveKey) as? Date ?? self.endDate
self.album = userDefaults.string(forKey: k.UserDefaultsSaveKeys.albumSaveKey) ?? self.album
print("Checking \(userAlreadyExist(kUsernameKey: k.UserDefaultsSaveKeys.albumSaveKey) )")
}
//Save - Save to local(NSUserDefaults):
func saveData() {
userDefaults.set(self.byActivity, forKey: "SavedByActivity")
userDefaults.set(self.postType, forKey: "SavedPostType")
userDefaults.set(self.hashTags, forKey: "SavedHashTags")
userDefaults.set(self.startDate, forKey: "SavedStartDate")
userDefaults.set(self.endDate,forKey: "SavedEndDate")
userDefaults.set(self.album,forKey: k.UserDefaultsSaveKeys.albumSaveKey)
}
//Testing function
func userAlreadyExist(kUsernameKey: String) -> Bool {
return userDefaults.object(forKey: kUsernameKey) != nil
}
}
Try this?尝试这个?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
filterViewModel.fetchData()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisppear(animated)
filterViewModel.saveData()
}
I would advise you to check if is saved.我建议您检查是否已保存。
userDefaults.string (forKey: k.UserDefaultsSaveKeys.albumSaveKey)
if it remains, then check the keys:如果仍然存在,请检查密钥:
userDefaults.set (self.byActivity, forKey: "SavedByActivity")
userDefaults.set (self.postType, forKey: "SavedPostType")
userDefaults.set (self.hashTags, forKey: "SavedHashTags")
userDefaults.set (self.startDate, forKey: "SavedStartDate")
userDefaults.set (self.endDate, forKey: "SavedEndDate")
You can try something like writing a general save method in your FilterModel:您可以尝试在 FilterModel 中编写通用保存方法:
func saveValue(_ value: Any, forKey key: String) {
UserDefaults.standard.set(value, forKey: key)
}
Then call it in your delegate methodes like that:然后像这样在您的委托方法中调用它:
func didButtonToPressed() {
//TODO: Present our custom calendar
let calendarController = CalendarPickerViewController(
baseDate: Date(),
selectedDateChanged: { [weak self] date in
guard let self = self else { return }
self.filterModel.saveValue(date, forKey: "SavedEndDate")
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
})
self.present(calendarController, animated: true, completion: nil)
}
Make sure that the key you are using to save the values are the same as the key you are retrieving it.确保您用于保存值的密钥与您检索它的密钥相同。
Also saving data in deinit is not a good practice, as deinit have some other purpose, is called when an instance is deallocated to free memory.在 deinit 中保存数据也不是一个好习惯,因为 deinit 有其他用途,当实例被释放以释放 memory 时会调用它。 And this is not happening immediately after a view is disappeared from the screen.这不会在视图从屏幕上消失后立即发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.